Introduction
Akita is a lattice-based polynomial commitment scheme, or PCS, implemented in Rust. Akita lets a prover commit to a large table and later prove an evaluation of the multilinear polynomial represented by that table. The verifier checks the proof without receiving the whole table. Akita uses transparent setup, so it needs no trusted ceremony. Its production parameters provide 128-bit post-quantum security under Module-SIS.
Akita's small proofs are one of its strongest advantages. Current production benchmarks produce opening proofs of roughly 65 to 80 KB. This contrasts with hash-based post-quantum polynomial commitment schemes, which produce proofs of hundreds of kilobytes at the same polynomial sizes Akita supports.
The codebase implements a standalone PCS that other proof systems can use. Its first major integration is Jolt, a zero-knowledge virtual machine, or zkVM, that proves the correct execution of 64-bit RISC-V programs.
Our claim: Akita is the first production-ready lattice-based polynomial commitment scheme. Earlier systems such as Greyhound showed that lattice commitments could be practical. Akita improves on that line of work and adds the validation, portability, verifier isolation, and integration work needed for deployment.
Why Akita exists
Many proof systems deployed today commit to their data with elliptic curve cryptography. Groth16, Plonk, and Bulletproofs are prominent examples. Their commitments are compact and well understood, but a sufficiently powerful quantum computer could break the assumptions behind them.
The commitment is often the part of the proof system that carries this assumption. The surrounding protocol checks polynomial identities using algebra and random challenges. Replacing the PCS with a post-quantum PCS can therefore protect the complete proof without replacing every other protocol in the system.
Hash-based commitments provide one post-quantum path. They are well developed, but they tend to produce larger proofs and require more prover memory. Akita takes the lattice path. It uses structured lattice problems to obtain post-quantum security, compact proofs, and a commitment operation that can preserve sparse inputs.
What a polynomial commitment proves
A proof system often represents a computation as one or more large tables. The prover has the tables. The verifier wants confidence in a calculation over them without downloading the tables or repeating the calculation.
The word polynomial describes how the proof system gives a table useful algebraic structure. A table with entries defines a multilinear polynomial with variables. Each variable appears with degree at most one. For example, eight table entries define a polynomial in three variables because three bits select one of eight positions.
The polynomial also has values away from those eight table positions. A larger proof system uses evaluations at such points to combine many table checks into a small number of claims.
A PCS gives the prover and verifier four operations:
| Operation | What it does |
|---|---|
| Setup | Creates the public information needed by commitments and proofs |
| Commit | Fixes one or more polynomials and produces a compact public commitment |
| Prove | Produces evidence for claimed evaluations of the committed polynomials |
| Verify | Checks the claims against the commitment and public setup |
The commitment fixes the data before the evaluation point is known. A valid opening should not let the prover change that data after seeing the point.
Akita currently exposes multilinear commitments. Its folding protocol needs tensor structure rather than multilinearity itself, so the same architecture can support a future univariate interface.
Why Akita uses lattices
The choice of commitment changes the security, proof size, prover work, and verifier work of the complete proof system.
| Approach | Main advantage | Main cost |
|---|---|---|
| Elliptic curves and pairings | Very small proofs and fast verification | The security assumptions are not post-quantum, and some schemes require a trusted setup |
| Hash functions | Post-quantum security and transparent setup | Proofs often contain many hash tree paths, which increases proof size and data movement |
| Structured lattices | Post-quantum security with useful algebraic structure | Parameters, norm bounds, and optimized ring arithmetic must agree exactly |
Akita writes each field value as small signed digits and multiplies those digits by a public matrix. A zero digit contributes nothing to that product. The prover can therefore keep sparse polynomials sparse instead of first expanding them into a dense encoding. This is useful for one-hot tables such as those created by Jolt memory checks.
Module lattices also connect Akita to the direction taken by post-quantum cryptography more broadly. NIST standardized module lattice systems ML-KEM for key establishment and ML-DSA for signatures. Akita brings module lattice algebra to polynomial commitments, which makes it a natural commitment layer for proof systems that need to reason about post-quantum protocols.
The Why lattices? chapter develops this comparison, the sparse advantage, and the protocol lineage in more detail.
How Akita makes the proof small
Akita combines lattice commitments with repeated folding. A fold replaces one large claim with a smaller claim that has the same form. The proof records why the replacement is valid. Akita can then apply the same step again instead of sending evidence proportional to the original table.
First, the prover commits to small signed digits using public matrices over polynomial rings. Binding rests on Module-SIS. Informally, Module-SIS says that it is hard to find a short nonzero input that a public matrix maps to zero.
Second, Akita follows a fold schedule. This is a plan that says how large each intermediate claim will be and which security limits the verifier will enforce.
The benchmark suite currently tests 13 cases. Each case fixes the arithmetic field and the shape of the polynomial data. It also fixes how many polynomials are opened and how the prover handles the public setup calculation. Twelve cases use seven fold levels. A fold level means one reduction step. The seventh level is the terminal fold, where the verifier checks the remaining response directly. One benchmark case divides the work into eight chunks during its first two steps and uses eight fold levels in total.
For a concrete example, consider the benchmark that opens one dense polynomial over Akita's 128-bit field. Dense means that every position in the polynomial's table may contain an arbitrary element of that field. This polynomial has 28 variables, so its table contains field values. The fold schedule reduces the data that remains to be checked as follows:
| Fold level | Field values entering the level |
|---|---|
| L0 | 268,435,456 |
| L1 | 55,332,544 |
| L2 | 3,892,032 |
| L3 | 1,064,256 |
| L4 | 488,384 |
| L5 | 255,488 |
| L6, terminal | 128,768 |
The first six levels send a new commitment and a few small field values. They also send short algebraic proofs, called sumchecks, that connect the next claim to the previous one. Those messages occupy 19,912 bytes in this benchmark case. L6 performs the terminal check, adds a 4-byte number used when choosing the folding challenge, and sends the remaining response directly. The complete fold payload is therefore 19,916 bytes.
That complete proof is 73,018 bytes. Its 53,102-byte terminal response contains three parts:
| Terminal part | What it contains | Size |
|---|---|---|
| The folded witness response, 16,384 coefficients stored with a compact integer encoding called Golomb coding | 20,334 bytes | |
| The 512 opening values needed by the final check | 8,192 bytes | |
| The 1,536 inner commitment values needed by the final check | 24,576 bytes |
Another fold is useful only when the bytes it removes from this remaining response exceed the bytes needed to prove the extra fold. The planner stops at the least expensive valid point. Across the latest complete profile run, all 13 production cases passed with proofs from 66,600 to 79,527 bytes. The benchmark report guide explains how to inspect the current totals and the byte cost of every fold.
Finally, the verifier checks the selected schedule, replays the same transcript, checks every fold, and verifies the clear terminal response before it accepts the claimed evaluation.
Akita does not need a trusted ceremony or a secret trapdoor. The prover may cache expanded public setup for speed, but correctness does not depend on anybody keeping a setup secret. The current PCS proof is not itself zero knowledge. Applications that require witness privacy must account for that boundary. The zero-knowledge roadmap describes the planned privacy layer.
The How it works section follows the complete protocol from configuration through setup, commitment, folding, and verification. The security model gives the exact Module-SIS assumptions and parameter checks.
Built as a complete system
Akita treats deployment engineering as part of the cryptographic design. The repository ships external schedule artifacts, checked security parameters, a separate verifier package, canonical proof encoding, and portable optimized arithmetic. The verifier rejects malformed public input with structured errors instead of panicking. The prover preserves sparse inputs and streams selected matrix operations in bounded chunks.
Memory is another scaling advantage. An arbitrary dense source still occupies one field element per table entry, but Akita can take ownership of that buffer instead of copying the complete table. Its folding schedules replace the source with progressively smaller intermediate data. For large supported tables, the prover's working memory beyond the source polynomial grows more slowly than the polynomial itself. This is in contrast to standard hash-based PCS provers, which usually materialize an encoded word and a hash tree during commitment, then retain both to answer later openings. The memory for those objects grows linearly with the polynomial size.
The 65 to 80 KB figures cover the Akita commitment proof. The host proof system contributes its own proof data.
Jolt is the first demanding host for these boundaries. It exercises Akita inside another verifier and accounts for proof bytes, verification work, memory, serialization, and guest failures as one integration problem. The same interfaces are designed for other proof systems to adopt.
The Built for production chapter explains the engineering evidence behind the production-ready claim. The Reviewing and auditing Akita chapter maps the security boundaries to the code, generated artifacts, and tests that enforce them.
Continue through the Book
Choose the next section by what you want to do:
| Goal | Continue with |
|---|---|
| Run Akita or integrate the PCS | Usage |
| Learn the mathematical ideas from the beginning | Foundations |
| Follow the protocol and implementation | How it works |
| Review the assumptions and verifier boundary | Reviewing and auditing Akita |
| See planned work rather than current behavior | Roadmap |
The Book explains each mechanism before pointing to its implementation. Current code is the authority for runtime behavior. Live specifications record accepted designs that have not yet been fully folded into the Book, while archived specifications record history rather than current requirements.
Why lattices?
Akita uses structured lattices because they offer more than post-quantum security. Their algebra fits polynomial commitments. Linear operations can preserve sparse data, while ring structure supports the fast arithmetic needed by a large prover.
This chapter explains that choice in the wider commitment landscape.
The polynomial commitment carries the assumption
Many proof systems check polynomial identities using algebra and random challenges. Those checks do not need an elliptic curve hardness assumption. The PCS fixes the polynomials and later proves their evaluations. In these systems, the PCS is the part that introduces the computational assumption.
This division gives system designers a focused post-quantum upgrade path. They can replace a curve-based PCS with Akita while preserving much of the protocol that constructs and checks the polynomial identities.
When the PCS is the host system's main computational assumption, replacing it with Akita changes the security of the complete proof. Any additional computational assumptions in the host must provide their own post-quantum security.
Three polynomial commitment approaches
The main approaches make different choices about proof size, setup, and prover work.
Elliptic curves and pairings
Curve-based commitments support very small proofs and fast verification. This has made them a common choice in deployed systems such as Groth16 and Plonk. Their binding rests on discrete logarithm assumptions that a large quantum computer could break. Some pairing-based systems also require a trusted setup ceremony.
Hash functions
Hash-based commitments use a conservative post-quantum foundation and need no trusted setup. A prover usually encodes the complete object and commits to it with a hash tree. An opening includes authentication paths through that tree.
This design is general, but it moves substantial data. The prover must hash the dense encoding, and the proof carries the paths needed to authenticate opened positions. These costs are a major part of the proof size and memory traffic in many post-quantum proof systems.
In a standard in-memory prover, the encoded word and hash tree require memory that grows linearly with the polynomial size. A prover can reduce RAM by recomputing data or moving it to external storage, but then pays more work or disk traffic.
Structured lattices
A lattice commitment applies a public linear map to a representation with small coefficients. Akita performs that map over polynomial rings. The ring structure turns large matrix products into fast polynomial operations, while the small coefficient bounds provide the binding statement priced by Module-SIS.
This gives Akita a transparent commitment with post-quantum security and useful algebra. Every layer agrees on the exact dimensions, decomposition ranges, challenge distributions, and accepted response bounds. Akita makes those choices explicit in generated schedules and validates them at the verifier boundary.
Sparse data stays sparse
Akita first decomposes a field value into small signed digits. It then multiplies those digits by a public matrix. A zero digit adds nothing to the result, so the prover does not need to process it as a nonzero matrix input.
This property is important for a one-hot polynomial. Divide its evaluation table into blocks. Each block contains one value equal to one, and every other value is zero. A dense encoding stores every zero. A hash tree also hashes every encoded position. Akita can store the hot positions and perform commitment work for the nonzero digits.
Jolt memory checking creates tables with this structure. Akita provides one-hot polynomial sources and generated one-hot configurations for them. The same principle applies to other applications whose committed data has a sparse representation.
Sparse input does not make every later proof operation sparse. Folding combines values and can produce dense intermediate witnesses. The gain begins at the commitment boundary and continues wherever the operation can preserve the sparse representation. The prover code makes each transition explicit instead of hiding it behind a dense polynomial interface.
Ring structure supports fast arithmetic
Akita groups coefficients into elements of a polynomial ring. Public matrices then become matrices of ring elements rather than unstructured scalar matrices. The implementation uses number theoretic transforms to multiply these ring elements quickly.
The selected schedule may use different ring dimensions for different matrix roles and fold levels. Larger rings reduce the number of independent matrix entries, but they also change transform cost, exact arithmetic bounds, and available parallelism. The offline planner compares those costs and emits a concrete schedule. Normal proving and verification consume the generated result instead of searching again.
The NTT, CRT, and fast ring arithmetic chapter explains the arithmetic. Configuration and planning explains how generated schedules select it.
Part of the post-quantum direction
Module lattices already support major post-quantum standards. NIST standardized ML-KEM for key establishment and ML-DSA for signatures. Akita uses module lattice algebra for a different purpose: binding polynomial commitments.
The shared algebra creates a natural path for proof systems that need to prove statements about lattice-based encryption, signatures, and related protocols. The host can represent those computations using the same broad family of ring and module operations instead of translating them into an unrelated commitment model.
Akita therefore serves two roles. It can replace a curve-based commitment in a proof system that needs post-quantum security. It can also provide the commitment layer for proving the post-quantum primitives that modern cryptographic systems are beginning to use.
From practical commitments to repeated folding
Akita follows a line of work that includes LaBRADOR, Greyhound, and Hachi. These systems established compact lattice proofs and practical polynomial openings. Greyhound and Hachi produced small Module-SIS-based proofs, but their verifiers still performed work that grew roughly with the square root of the polynomial size.
Akita makes the reduction repeatable. It replaces one large opening relation with a smaller relation of the same general form, then folds again. A generated schedule continues this process until the remaining claim is small enough for direct verification.
Repeated folding is what turns the lattice commitment into a PCS with a small verifier. It also creates the need for exact transcript binding, per-level parameters, setup contribution checks, and terminal verification. The How it works section develops those mechanisms.
Multilinear today, broader tensor structure tomorrow
The current API commits to multilinear polynomials represented by evaluation tables. A table with entries has one axis for each of its variables, so it already has tensor structure.
Akita's folds use that tensor structure. They do not rely on multilinearity as the only possible interpretation of the data. The coefficients of a univariate polynomial can also be arranged as a tensor and folded one axis at a time.
The repository does not yet expose a univariate commitment interface. The protocol architecture can support one without changing the central reason for using lattices: efficient linear commitments over structured ring data.
Built for production
Akita treats deployment engineering as part of the cryptographic protocol. A proof system can adopt the PCS only when its parameters, proof format, verifier, optimized arithmetic, and operational tools agree on one exact design.
Akita is the first implementation in this line built around that complete requirement.
From research result to deployable primitive
Related public implementations such as LaBRADOR, LaZer, RoKoko, and Jindo made important lattice proof techniques reproducible. Their code is organized around research experiments, benchmark configurations, or narrow machine targets.
Akita takes the next step. It provides a standalone PCS that another proof system can integrate as a maintained dependency. The planner chooses parameters, and normal builds consume generated artifacts. Separate prover and verifier paths share canonical serialization. Portable arithmetic, profiling, and end-to-end host integration complete the deployment system.
Production readiness comes from agreement across that complete system.
External schedule artifacts are fixed before proving
An Akita fold uses concrete ring dimensions, digit decompositions, challenge spaces, and response bounds. Those choices determine security, proof shape, and the checks performed by the verifier. A proof must not be allowed to define them.
The planner searches this space offline. It prices complete proof schedules,
checks their security requirements, and emits reviewed .aks artifacts. The
host loads the selected artifact into one validated catalog shared by the
configured prover and verifier. Neither
runs the planner during normal proving or verification.
The public opening statement carries a 32-byte digest that names one row in that catalog. This digest is not a schedule and is not part of the proof payload. The verifier accepts it only when it matches a row in its own enabled catalog. It then reads the dimensions, bounds, and expected proof shape from that local row. An unknown digest is rejected, so a prover cannot supply an unchecked schedule.
This separation keeps verification small and deterministic. Parameter changes also appear as ordinary generated source changes that code review and continuous integration can inspect.
The Configuration and planning chapter explains the catalog keys and validation path. The Security model explains how the repository prices Module-SIS and response bounds.
The verifier is an independent boundary
Verifier-only consumers can depend on akita-verifier, akita-types, and
akita-config without pulling in prover polynomial backends or planner search.
This crate boundary keeps proving convenience code away from the code that
accepts or rejects a proof.
Every verifier facing artifact is untrusted. The verifier checks lengths,
shapes, schedule identity, setup identity, and canonical field encodings before
using them. Malformed input returns AkitaError or SerializationError. It
must not trigger a panic or an unchecked allocation.
This rule is enforced as a repository contract rather than an informal coding preference. The Verification chapter describes the complete boundary and its rejection rules.
Proof identity is explicit
Akita binds the configuration, setup identity, opening layout, selected schedule, commitments, points, and claimed evaluations into the transcript. The prover and verifier derive challenges only after they have committed to the same public statement.
Proofs and setup artifacts use canonical encodings with checked decoding. The verifier derives the expected proof shape from the public statement and selected schedule before decoding. Applications pin an exact Akita revision when they exchange proof artifacts because protocol evolution can change those bytes.
The Transcript and instance binding chapter follows the absorption order and challenge schedule. The Usage section explains the artifact lifecycle expected from an integrating application.
Optimized arithmetic remains portable
Large lattice operations need optimized ring arithmetic. Akita provides scalar implementations together with AVX2, AVX-512, and NEON paths. Runtime dispatch selects an implementation supported by the host CPU. Differential tests compare optimized outputs with portable reference paths.
The implementation also distinguishes arithmetic representations by their exact bounds. Some AVX-512 kernels use 50-bit residues in 64-bit lanes, while ordinary i32 transforms retain their own dispatch rules. These are backend choices. They do not change the proof statement or public setup identity.
Portable reference paths make correctness testable on ordinary development machines. Optimized paths allow the same protocol to use wide instructions on production hosts. The Optimizations and NTT, CRT, and fast ring arithmetic chapters explain these layers.
The prover controls memory as well as time
The committed polynomial is often the largest object in the application. The current dense API receives a materialized table. When the application passes an owned field buffer, Akita reuses that buffer instead of making another complete copy.
The generated fold schedule replaces the source with progressively smaller intermediate data. At large supported polynomial sizes, this additional working state grows more slowly than the source table. The dense digit cache is capped at 512 MiB. Large ring relation and quotient transforms operate on bounded chunks instead of retaining complete transformed matrices.
The current 128-bit dense benchmark makes this concrete. Its field elements occupy a 4.0 GiB source table. The first fold reduces that table to 55,332,544 field elements, about one fifth as many. The complete benchmark process peaks at about 5.1 GiB while it constructs setup, commits, proves, and verifies.
One-hot sources store their hot positions instead of a full table. Setup matrices come from a deterministic public stream and can be materialized only to the capacity required by a deployment. Prepared NTT entries are reusable compute state rather than part of public setup identity.
The prover exposes explicit release points for hosts that need to free shared matrix state before a recursive suffix. These controls let an integration make memory policy visible and measurable instead of relying on hidden global caches.
A fully streamed dense source could remove the need to store the original table inside Akita. That source path is not part of the current production API.
Performance claims come from complete proofs
The profile harness measures setup, commitment, proof generation, serialization, and verification for complete opening statements. It reports proof bytes, peak resident memory, selected schedule geometry, and separate phase timings.
Representative dense, one-hot, and grouped profiles across the supported field sizes currently produce Akita proof payloads of roughly 65 to 80 KB. The profile records the exact statement and configuration behind each result. This keeps a proof size attached to the workload that produced it.
Continuous integration compares a pull request with its merge base on the same runner. It also checks external schedule artifact drift, portable and optimized arithmetic, feature combinations, verifier dependencies, documentation links, and malformed input rejection.
The Profiling chapter explains how to reproduce and interpret these measurements.
Jolt exercises the complete boundary
Jolt is Akita's first major integration. It is a zkVM that proves correct execution of 64-bit RISC-V programs. Its memory checks create large one-hot tables, which makes it a natural host for Akita's sparse commitment path.
The integration also exercises more than proving speed. Akita proof bytes must cross a host and guest boundary. The guest must decode hostile bytes, construct the exact public statement, resolve a shipped schedule, and verify within its memory and execution limits. The host must preserve setup identity and transcript inputs across the same boundary.
These requirements shaped the separate verifier package, canonical artifact format, setup narrowing, cache release controls, and integration harness. They are general PCS boundaries, not Jolt specific shortcuts. Other proof systems can use the same interfaces.
The Jolt recursion chapter covers the current host and guest path.
What the production claim means
Akita combines the protocol and system work required for another proof system to adopt it:
- generated parameters tied to the verifier's checks;
- a standalone verifier with a strict hostile input boundary;
- canonical proof and setup artifacts;
- portable and optimized arithmetic with differential tests;
- sparse and streaming prover paths with explicit memory policy;
- complete profiling and integration harnesses.
These are not surrounding conveniences. They determine whether the same cryptographic statement survives planning, proving, serialization, verification, optimization, and host integration. Akita treats that agreement as part of the primitive.
Reviewing and auditing Akita
Akita is designed so that a reviewer can follow a public claim from the Book to the code that enforces it. The main boundaries are visible in crate dependencies, external schedule artifacts, transcript inputs, checked decoding, and verifier rejection paths.
This chapter maps the starting points for a security argument and a code audit.
Start with the accepted statement
An Akita proof does not stand alone. The verifier accepts a statement that includes ordered commitment groups, opening points, claimed evaluations, a configuration, public setup, and a generated schedule selection.
Begin an audit by writing down that complete statement. Check which values come from the host application and which values the verifier derives. Then confirm that the transcript binds every public value that can change the meaning of the proof.
The Commitment API explains the public object lifecycle. Transcript and instance binding gives the protocol order. Verification follows the checks made before and during replay.
Treat every verifier input as hostile
Proof bytes, setup artifacts, schedules, commitments, points, evaluations, and
length fields may all come from an attacker. Verifier reachable code must
reject malformed data with AkitaError or SerializationError.
The no panic contract prohibits verifier reachable panic!, assert!,
unwrap, unchecked indexing, and unbounded allocation unless an earlier
boundary has established the required invariant. Checked arithmetic is part of
the same rule because an overflow can otherwise turn a small encoded shape into
the wrong allocation or loop bound.
Review the boundary in this order:
- Canonical decoding and size limits.
- Configuration and generated schedule admission.
- Setup capacity and setup identity.
- Opening claim shape and group order.
- Transcript binding before each challenge.
- Response bounds and relation checks.
- Terminal consistency checks.
This order follows the path from attacker controlled bytes to the final cryptographic decision.
Crate boundaries carry security meaning
Akita uses separate crates so that verifier code does not depend on the planner or prover implementation.
| Crate | Review role |
|---|---|
external jolt-field and akita-algebra | Field, ring, transform, and polynomial arithmetic |
akita-serialization | Canonical encoding and checked decoding |
akita-transcript and akita-challenges | Instance binding and challenge derivation |
akita-sumcheck | Shared sumcheck proof types and drivers |
akita-types | Public proof, setup, schedule, commitment, and claim shapes |
akita-planner | Offline schedule search and cost evaluation |
akita-schedules | External schedule artifact decoding, admission, and lookup |
akita-config | Concrete policy and schedule admission |
akita-setup | Public setup construction and setup artifacts |
akita-prover | Commitment and proof generation |
akita-verifier | Proof replay and rejection of invalid statements |
akita-pcs | End to end orchestration and broad public exports |
Verifier only applications should depend directly on akita-verifier,
akita-types, and akita-config. If verifier replay begins to require a
prover polynomial backend or planner search, the dependency change itself is a
security review event.
The Architecture overview contains the complete crate graph and core type map.
Check one source of truth for each concept
Security and sizing logic must use the same primitive that the verifier enforces. A planner estimate, certificate check, and runtime verifier must not carry separate versions of one bound.
The repository follows one canonical function per concept. Generic checked
integer formulas live in akita_error::checked. Schedule validation belongs to
the configuration and schedule admission path. Transcript labels and order
belong to the transcript implementation. Serialization validity belongs to the
type that owns the encoding.
When a review finds two helpers that appear to compute the same security value, the right question is which one the verifier trusts. Thin wrappers and copied formulas make that answer harder to establish and should not become alternate sources of truth.
Schedule artifacts need review too
Normal builds load approved external schedule artifacts. The planner is an offline tool, but its output selects the dimensions, challenge rules, bounds, and opening methods that the verifier accepts.
A schedule review should establish:
- the lookup key describes the complete ordered opening layout;
- the selected row belongs to the artifact family bound to the configuration;
- every fold satisfies the accepted Module-SIS and response policies;
- setup capacity covers each direct matrix use;
- setup offloading metadata matches the carried setup commitment;
- the terminal parameters cover the remaining relation.
Generation scripts and continuous integration byte-compare committed .aks
artifacts with fresh planner output. An external schedule artifact is still
protocol source. Review changes to it with the same care as handwritten
verifier code.
The Configuration and planning, Setup offloading, and Security model chapters divide this review into its protocol parts.
Follow transcript identity end to end
The transcript turns public objects and prover messages into challenges. If the prover and verifier absorb different statements, they are no longer executing the same protocol.
Check that both sides bind the same configuration, setup identity, schedule, claim layout, commitments, points, and evaluations in the same order. Then check that each prover message is absorbed before the challenge that depends on it. Group order and point coordinates are protocol data, not presentation details.
Logging transcript tests record the schedule of absorb and squeeze events. Hardening tests mutate public values and confirm that verification rejects the changed statement. These tests provide useful evidence, but the review should also establish why every meaning changing value appears in the transcript.
Review optimized arithmetic against a reference
Akita uses scalar, AVX2, AVX-512, and NEON arithmetic. Unsafe code and vector kernels deserve their own pass because a platform specific error can change a commitment or verifier relation without changing high level Rust code.
For each optimized kernel, identify:
- The scalar or mathematical reference operation.
- The accepted input range and intermediate bound.
- The runtime feature check that selects the kernel.
- Differential tests over boundary values and random inputs.
- Exact reduction before values cross into canonical serialization or transcript code.
The Optimizations chapter maps the main kernels. The NTT, CRT, and fast ring arithmetic chapter explains the representations and exact reconstruction bounds.
Understand what each repository source proves
The repository has several forms of documentation, and they have different jobs.
| Source | What it establishes |
|---|---|
| Current code | Runtime behavior and enforced API boundaries |
| External schedule artifacts | Concrete schedules and parameters admitted by normal builds |
| Live specifications | Accepted designs that still contain details not folded into the Book |
| The Book | The maintained explanation of current behavior |
| Tests | Evidence for selected valid cases, rejection paths, and cross implementation agreement |
| Archived specifications | Design history, not current requirements |
When these sources disagree, record a documentation or implementation defect. Do not combine parts from different versions into an unstated protocol. The Spec index identifies live and historical design records.
Suggested audit paths
Different reviews can start at different boundaries:
| Review goal | Start with | Continue with |
|---|---|---|
| Binding and security parameters | Polynomial commitments and binding | Security model and generated schedules |
| Transcript soundness | Transcript and instance binding | Transcript labels, logging tests, and proof replay |
| Malformed input safety | Verification | Serialization, checked allocation, and rejection tests |
| Setup correctness | Setup and commitment | Setup capacity, persistence, and setup offloading |
| Arithmetic correctness | NTT, CRT, and fast ring arithmetic | Scalar references, vector kernels, and differential tests |
| Host integration | Usage | Verifier only integration and the host adapter |
A complete audit eventually crosses all of these paths. The table identifies a clear first boundary for each kind of question.
Using Akita
Akita gives a proof system a complete polynomial commitment interface. An application commits to a large table, claims the value of that table's multilinear extension at a chosen point, and asks Akita to prove the claim. The verifier checks the proof without receiving the table.
Akita is built for use as infrastructure. The repository provides generated security parameters, optimized prover code, a compact proof format, and a separate verifier package. A host proof system can use the complete Rust API or carry only the verifier into a smaller trusted environment.
The complete lifecycle
An Akita integration performs four operations.
| Operation | What the application supplies | What Akita returns |
|---|---|---|
| Setup | A configuration and maximum workload size | Public setup data and reusable prover state |
| Commit | One or more polynomial tables | A public commitment and private prover data |
| Prove | The committed tables, opening points, and claimed values | One batched opening proof |
| Verify | Public setup, commitments, claims, and proof bytes | Success or a structured error |
The shortest complete path looks like this:
choose a configuration
↓
build and prepare setup
↓
commit to polynomial groups
↓
state the opening points and values
↓
prove and encode
↓
decode and verify
The first proof chapter runs this full path with one dense polynomial. It uses a real external schedule artifact and the same public API used by larger integrations.
What Akita commits to
The current API commits to multilinear polynomials represented by their values on the Boolean cube. A polynomial with variables has entries. Akita supports arbitrary dense tables and a compact one hot representation for tables with one selected entry in each fixed size chunk.
Applications may commit to several polynomials at once. Polynomials with the same number of variables and the same opening point form one commitment group. A proof may contain several ordered groups, and each group may use its own point. Akita binds the group order, commitments, points, claimed values, configuration, and selected proof schedule into the transcript.
This group model lets a host combine earlier commitments with a final group in one proof. It also lets Akita preserve structured inputs instead of expanding every table into a dense allocation.
Choose your path
| If you want to | Read |
|---|---|
| Run one complete proof | Your first proof |
| Pick a field and input representation | Choosing a configuration |
| Integrate commitment, proving, and verification | Integrating the PCS |
| Carry only verification into another environment | Verifier only integration |
| Choose Cargo features | Feature flags |
| Measure time, memory, and proof size | Profiling |
| Diagnose a failed run | Troubleshooting |
| Add Akita to another proof system | Integrating with a proof system |
| Verify Akita inside a zkVM | Jolt recursion |
Readers who want to understand the protocol itself can continue to How it works. Readers who need the mathematical ideas first can start with Foundations.
Which crate to use
The repository separates proving from verification on purpose.
| Crate | Role |
|---|---|
akita-pcs | Complete setup, commitment, proving, and verification interface |
akita-config | Production configurations and trusted artifact validation |
akita-schedules | External artifact decoding, row audit, and owned catalog lookup |
akita-prover | Polynomial representations, prepared compute state, and prover kernels |
akita-verifier | Verification without prover polynomial backends or planner search |
akita-types | Proofs, commitments, claims, schedules, and setup types shared across the boundary |
akita-transcript | The transcript that derives proof challenges from the public statement and prior messages |
An application that proves and verifies can begin with akita-pcs. A small
verifier should depend directly on akita-verifier, akita-types, and
akita-config. Pin every Akita crate to the same revision because a proof and
its verifier must use the same protocol format.
Akita chooses the proof plan
The application chooses the field, data shape, and group layout. Akita then resolves an approved row from the catalog supplied by the application. That row fixes the ring dimensions and all later fold parameters.
This division keeps the application interface small. It also keeps parameter search out of the verifier. The verifier uses the exact catalog bound to its preprocessing or setup package and replays the statement-selected approved row.
The configuration guide explains the choices an application should make and the choices Akita deliberately makes for it.
Your first proof
The quickest way to understand Akita is to run one complete commitment and opening proof. The repository includes a checked example that uses the real production API from setup through verification.
Run this command from the repository root:
cargo run -p akita-pcs --release --example quickstart
The first release build compiles the complete proving stack. Later runs reuse those build results. A successful run ends with output of this form:
Akita proof verified
The complete source is
crates/akita-pcs/examples/quickstart.rs.
The normal Cargo checks compile this example with the public API. The chapter
therefore stays tied to code that works.
The statement being proved
The example uses fp128::Dense, Akita's direct configuration for arbitrary
values in its 128 bit field. It creates a table with field elements.
That table represents a multilinear polynomial with 14 variables.
The example then chooses a point with 14 coordinates and evaluates the multilinear polynomial there. This value is the public claim. In a larger proof system, the host protocol usually produces the table, point, and claimed value.
#![allow(unused)] fn main() { type Config = fp128::Dense; type F = fp128::Field; const NUM_VARS: usize = 14; let polynomial = DensePoly::from_field_evals(NUM_VARS, &evaluations)?; let evaluation = evaluate_multilinear(&evaluations, &point); }
The helper that computes evaluation is independent of the Akita prover. It
exists to give the verifier a concrete public value to check.
Load schedules and build reusable setup
The configuration determines the expected schedule family and policy. The
application loads approved artifact bytes from its own storage; Akita validates
them before setup or proof work begins. setup_prover then sizes public matrix
data from the exact rows in that catalog.
#![allow(unused)] fn main() { let artifact_bytes = std::fs::read("parameters/fp128_dense.aks")?; let scheme = AkitaCommitmentScheme::<Config>::from_schedule_artifact( &artifact_bytes, akita_params::ChunkedWitnessCfg::default_non_chunked(), )?; let setup = scheme.setup_prover(NUM_VARS, 1)?; let backend = std::sync::Arc::new(CpuBackend::new(setup.expanded.clone())?); }
The prepared backend holds reproducible compute state such as transformed matrix prefixes. Applications should reuse it across commitments and proofs. Setup is public. Akita does not require a secret trapdoor or a trusted setup ceremony.
Commit to the polynomial
One call commits to one group of polynomials. This example has one polynomial and no earlier groups.
#![allow(unused)] fn main() { let source = backend.import_source(vec![polynomial])?; let commit_output = backend.commit( scheme.schedules(), &source, GroupContext::scheduler_without_precommitted_groups(), )?; }
The call returns two values:
committed_groupis public. The verifier receives it.private_handleretains the exact immutable source and commitment parameters.
The group context tells Akita which catalog row to use for the commitment. A later chapter explains how earlier commitment groups change this context.
Assemble the opening claim
An opening claim joins the point, claimed value, and commitment. The prover also supplies the reusable commitment handle. It cannot substitute another polynomial.
#![allow(unused)] fn main() { let prover_claims = OpeningClaims::from_groups(vec![ PolynomialGroupClaims::new( point.clone(), vec![evaluation], commit_output.committed_group.clone(), )?, ])?; let prover_data = SelectedProverOpeningData::from_committed_claims::<Config>( prover_claims, vec![commit_output.private_handle.clone()], scheme.schedules(), )?; let selection = prover_data.selection(); }
SelectedProverOpeningData checks that the public claims, commitment profiles,
private hints, and polynomial groups have the same order and shape. It also
selects the exact trusted catalog row for the complete batch.
Produce the proof
The prover starts a transcript with an application specific domain. This domain separates the proof from every other protocol that may use the same transcript construction.
#![allow(unused)] fn main() { const TRANSCRIPT_DOMAIN: &[u8] = b"akita/book/quickstart/v1"; let proof = scheme.batched_prove( &setup, prover_data, &backend, TRANSCRIPT_DOMAIN, BasisMode::Lagrange, )?; }
BasisMode::Lagrange means that the committed table contains values on the
Boolean cube. This is the standard representation for multilinear extensions
in proof systems.
Transport the proof
The proof is already the canonical Spongefish argument byte string. Store or send it directly; the public schedule bounds every message the verifier reads.
#![allow(unused)] fn main() { let proof_bytes: Vec<u8> = proof; }
Akita resolves the authenticated schedule before reading proof messages and rejects truncation, noncanonical atoms, and trailing bytes.
Verify with fresh public state
The verifier needs public setup, the commitment, the point, the claimed value, and the selected schedule row. It does not receive the polynomial or private prover state.
#![allow(unused)] fn main() { let verifier = scheme.verifier(scheme.setup_verifier(&setup)?)?; let verifier_claims = OpeningClaims::from_groups(vec![ PolynomialGroupClaims::new( point, vec![evaluation], &commit_output.committed_group, )?, ])?; let statement = GroupBatchStatement::new(selection, verifier_claims)?; verifier.batched_verify(&proof_bytes, TRANSCRIPT_DOMAIN, statement, BasisMode::Lagrange)?; }
Akita constructs fresh prover and verifier states and binds the complete public statement before deriving proof challenges, so a change to the group order, point, value, commitment, configuration, or schedule causes verification to fail.
What to change next
The example fixes its choices so that the lifecycle stays easy to follow. A real integration will choose them from the host protocol.
- Use Choosing a configuration to select the field and polynomial representation.
- Use Integrating the PCS for several polynomials, several opening points, or earlier commitment groups.
- Use Verifier only integration when verification must compile without the prover backend.
- Use Integrating with a proof system to connect Akita to a host protocol or recursive verifier.
- Use Profiling to measure a production size workload.
Choosing a configuration
An Akita configuration defines the field, committed data shape, security policy, and expected schedule-artifact family. The application chooses the family and supplies its approved artifact. Akita selects the exact row from the validated catalog.
This split is one of Akita's strengths. Applications make decisions about their own data. They do not tune ring dimensions or search for cryptographic parameters at runtime.
Start with the host field
Each production family has a base field for commitments and an opening field for evaluation points and claimed values.
| Family | Commitment field | Opening field | Common use |
|---|---|---|---|
fp32 | A 32 bit prime field | A degree 4 extension | Hosts built around small prime fields |
fp64 | A 64 bit prime field | A degree 2 extension | Hosts that want 64 bit base arithmetic |
fp128 | A 128 bit prime field | The same field | Hosts that already work over the full challenge field |
All three families target 128-bit quantum security under Akita's concrete lattice attack model. The smaller base fields use extension fields for opening points and claimed values. The host should choose the family whose opening field matches the values it needs to prove. The rings and fields chapter explains the construction.
Match the committed data
The next choice is the representation of the table.
| Representation | Use it when | Main benefit |
|---|---|---|
Dense | Entries may be arbitrary field elements | General purpose commitment path |
OneHot | Each fixed size chunk contains one selected position | Preserves the compact source and skips work for zero entries |
DenseBounded | Every centered coefficient fits the declared signed bound | Uses fewer commitment digits than full width dense data |
The direct fp128 types are fp128::Dense and fp128::OneHot.
fp128::DenseBounded accepts every u64 value and the corresponding negative
range. It uses the fp128_dense_bounded artifact family.
The bounded configuration enforces its range during commitment. This is useful
because the tighter range becomes part of the commitment profile and the
security calculation. Use ordinary Dense when the application cannot prove
the bound before calling Akita.
One hot is more than a label on a dense table. The prover stores selected indices and uses kernels written for that representation. Applications should keep structured data in this form instead of expanding it into a dense vector.
Describe the opening batch
A schedule is selected for the complete ordered batch. The selection depends on the following public shape:
- The number of commitment groups.
- The number of variables in each group.
- The number of polynomials in each group.
- The commitment profile carried by each group.
- The opening method fixed by the configuration and commitment profiles.
Polynomials in one group have the same number of variables and share one opening point. Polynomials with another arity or point belong in another group. The order of those groups is part of the proof statement.
The common direct case uses one group and
GroupContext::scheduler_without_precommitted_groups(). A grouped opening
commits earlier groups first, then commits the final group with
GroupContext::scheduler_with_precommitted_groups(&prior).
Direct and recursively offloaded setup checks
Every Akita proof reduces a large opening through a sequence of folds. The word
recursive in RecursiveCommitmentConfig<Cfg> refers to an additional setup
checking path. It lets the proof carry the large public setup contribution into
a later fold instead of asking the verifier to scan it directly.
Use the direct configuration first. It has the simplest setup and is the right choice for ordinary local verification. Use a shipped recursive configuration when the verifier environment makes direct setup evaluation expensive. The setup offloading chapter explains the complete protocol and its supported families.
Precommitted groups in a recursive grouped opening still use the base
configuration. The final group and the proof use
RecursiveCommitmentConfig<Cfg>. This preserves the commitment identity of the
earlier groups while selecting the recursive adapter for the complete opening.
Partition large prover work
The fp128 configuration module also provides multi chunk companions for selected production workloads. These configurations divide the witness relation into exact chunks during the first folds. They let the prover spread large work across a controlled partition without changing the public claim.
The profile name W8R2 means eight chunks in the first two folds (levels 0 and
1), followed by single-chunk folds. R3 extends that prefix to three folds
(levels 0, 1, and 2). The fp128 presets OneHotMultiChunkW2R3,
OneHotMultiChunkW4R3, and OneHotMultiChunkW8R3 offer two, four, and eight
chunks; DenseMultiChunkW8R3 offers eight chunks for dense sources.
RecursiveCommitmentConfig<fp128::OneHotMultiChunkW2R3>,
RecursiveCommitmentConfig<fp128::OneHotMultiChunkW4R3>, and
RecursiveCommitmentConfig<fp128::OneHotMultiChunkW8R3> combine each chunk
width with recursive setup offloading. Each preset uses its own trusted schedule catalog;
OneHotMultiChunk and DenseMultiChunk continue to use W8R2.
Multi chunk configurations are deployment choices for measured large
workloads. Begin with Dense or OneHot. Move to a multi chunk companion after
profiling the complete host application and confirming that its trusted
external catalog contains the required row.
Let the trusted catalog choose dimensions
Akita may use different ring dimensions for the commitment matrix, later relations, and different fold levels. The offline planner searches these choices under the same security rules that the verifier enforces. The selected row records the result.
Application code should not choose a fixed ring dimension. It should describe the field, data representation, and opening batch. This lets Akita improve offline schedules without changing the high level integration model.
Normal proving and verification never run the planner. They resolve a row from
the catalog supplied to the scheme instance. AkitaError::UnsupportedSchedule
means that catalog does not contain the exact request. The
troubleshooting guide
lists the information needed to diagnose that result.
Practical choices
Use these starting points:
| Application data | Starting configuration |
|---|---|
| Arbitrary values in the fp128 field | fp128::Dense |
| One selected entry in each fixed size chunk | fp128::OneHot |
Values known to fit the full u64 range | fp128::DenseBounded |
| A host using a small prime field | The matching fp32 or fp64 family |
| A verifier that must avoid a large direct setup scan | A supported RecursiveCommitmentConfig<Cfg> |
The first proof uses fp128::Dense. The
integration guide develops grouped openings and prepared
state. The profiling guide shows how to measure the selected
configuration at the host's real workload size.
Integrating the PCS
Akita gives a host proof system a clear boundary between private proving work and public verification. The prover owns the large polynomial tables and the compute state used to open them. The verifier receives commitments, claimed values, and one compact proof.
This boundary is designed for real integrations. A host can prepare setup once, reuse commitments across later claims, batch several polynomial groups into one opening, and carry the verifier into a package that has no prover backend or runtime planner.
The integration flow
A complete host follows this order:
- Choose a configuration for the host field and polynomial representation.
- Load and validate the approved external schedule artifact.
- Build prover setup for the largest supported workload from that catalog.
- Prepare the compute backend and keep it warm across proofs.
- Commit to each polynomial group and retain its private hint.
- Assemble the ordered opening claims for one proof.
- Let the catalog select the exact trusted row for that batch.
- Produce and encode the proof.
- Send the catalog identity, public statement, proof, and verifier setup.
- Restore the same approved catalog, decode under its expected shape, and verify.
The first proof runs this lifecycle with one polynomial. The chapters below explain how to turn that example into an application boundary.
Public and private data
Akita keeps the data split explicit.
| Data | Owner | Purpose |
|---|---|---|
| Original polynomials | Prover | Source data for commitment and opening |
| Commitment hints | Prover | Private data that connects each polynomial group to its commitment |
| Prepared compute state | Prover | Reusable transforms and backend resources |
| Trusted schedule catalog | Both | Approved external parameters used by setup, proving, and verification |
| Verifier setup | Public | Public matrix data and setup prefix commitments needed by verification |
| Commitments | Public | Values that fix the committed polynomial groups |
| Opening points and values | Public | The claims being proved |
| Schedule selection | Public | Identity of the approved catalog row used by the batch |
| Proof bytes | Public | Encoded evidence checked by the verifier |
The verifier never needs the original polynomial or the private commitment hint. The prover never chooses unchecked cryptographic parameters. Both sides use the same public configuration and trusted catalog identity.
Four contracts to preserve
An integration stays simple when it preserves four contracts.
Group contract
One commitment call creates one homogeneous group. Every polynomial in that group has the same number of variables. Every polynomial in one opening claim group shares one opening point.
Order contract
Group order is part of the public statement. The prover must keep commitments, hints, polynomials, points, and claimed values in the same order. Akita checks this shape before proving and binds it into the transcript.
Setup contract
The prover setup and verifier setup must describe the same public matrix stream and setup prefix commitments. Prepared CPU caches may differ because they are local compute state, not protocol identity.
Revision contract
The prover and verifier must use the same Akita protocol revision. Pin every Akita crate together and revalidate proof exchange when upgrading.
Read the focused guides
- Commitment groups and opening claims explains single groups, earlier commitments, and ordered batched claims.
- Setup and prepared compute state explains reusable public setup, verifier setup, backend caches, and persistence.
- Proof encoding and transcripts explains the public artifact, schedule selection, transcript domains, and decoding.
- Verifier only integration gives the direct verifier dependency path and call.
The protocol chapters under How it works explain why these contracts are sufficient. Application code can use them without reimplementing the protocol internals.
If Akita will sit inside a larger proof system, continue to Integrating with a proof system. That chapter explains the adapter around this PCS lifecycle: field conversion, statement ownership, artifact transport, and verifier placement.
Commitment groups and opening claims
Akita commits to polynomials in groups. Each group has a public commitment and an immutable private handle retaining its exact source. One backend can reuse these handles across independent and concurrent proofs.
Commit one group
Construct a backend from the public setup, then transfer the polynomials into its source storage. Each commit names the trusted catalog that selects the group's profile:
#![allow(unused)] fn main() { let backend = std::sync::Arc::new(CpuBackend::new(setup.expanded.clone())?); let source = backend.import_source(polynomials)?; let CommitOutput { committed_group, private_handle, } = backend.commit( scheme.schedules(), &source, GroupContext::scheduler_without_precommitted_groups(), )?; }
All polynomials in a source group must have the same number of variables and one supported source representation. Akita rejects a mixed group instead of padding smaller tables. Put polynomials with another size or representation in another group.
committed_group carries the public commitment and its frozen profile.
private_handle retains the exact source, parameters, and private commitment
material. It remains usable after the application drops source. Clone the
handle when opening the same commitment in another proof.
State one group's opening claims
Every public group claim contains one complete point, one claimed value for each polynomial, and the group commitment:
#![allow(unused)] fn main() { let group = PolynomialGroupClaims::new( opening_point, evaluations, committed_group.clone(), )?; let claims = OpeningClaims::from_groups(vec![group])?; let prover_data = SelectedProverOpeningData::from_committed_claims::<Config>( claims, vec![private_handle.clone()], scheme.schedules(), )?; let selection = prover_data.selection(); }
If the group contains four polynomials, evaluations contains four values in
the same order. The point has one coordinate for each polynomial variable.
The constructor selects one exact catalog row. The backend checks that each
handle belongs to it and matches the supplied public commitment and profile.
The proof checks the claimed evaluations against the retained source.
The returned selection is public and travels with the verifier statement. Opening accepts only the handles and public claims; the application cannot substitute a different polynomial table at proof time.
Open several groups in one proof
Separate groups may have different numbers of variables and different points. Akita keeps each point with its own group:
#![allow(unused)] fn main() { let claims = OpeningClaims::from_groups(vec![ PolynomialGroupClaims::new(point_a, values_a, commitment_a.clone())?, PolynomialGroupClaims::new(point_b, values_b, commitment_b.clone())?, PolynomialGroupClaims::new(point_c, values_c, commitment_c.clone())?, ])?; }
The final group is the last item. Every earlier item is a precommitted group. Build the commitment handle vector in exactly the same order. Each group binds its variable count, polynomial count, frozen profile, commitment, point, and claimed evaluations.
Before committing the final group, derive the ordered profiles of the earlier commitments:
#![allow(unused)] fn main() { let prior = PrecommittedGroupProfiles::from_profiles( prior_commitments.iter().map(|group| *group.profile()).collect(), )?; let final_source = backend.import_source(final_polynomials)?; let final_output = backend.commit( scheme.schedules(), &final_source, GroupContext::scheduler_with_precommitted_groups(&prior), )?; }
The grouped context selects a trusted catalog row keyed by the complete ordered
prefix and final group. Earlier independent commitments remain reusable in
later batches. PrecommittedGroupProfiles is nonempty by construction; the
independent case uses its own constructor.
Recursive grouped openings
A RecursiveCommitmentConfig<BaseConfig> uses setup offloading for supported
large verifier workloads. Commit the final group under the recursive catalog.
Earlier groups use the reviewed independent commitment profile from the base
catalog, supplied through GroupContext::explicit(&base_profile). The final
group uses GroupContext::scheduler_with_precommitted_groups(&prior).
This keeps one backend owner for the entire proof and preserves the independent public profiles of earlier groups. The proof's recursive catalog checks the complete ordered batch.
Dense and one hot groups in one batch
Import dense and one hot polynomials as separate homogeneous source groups. Their commitments have the same opaque handle type, so their handles can be placed in one ordered opening batch. Concrete CPU source operations remain inside the backend, and one hot data retains its compact representation.
The backend stores no catalog, so one backend commits every group. Pass each
group's producer catalog to its own commit, then commit the final group and
open the batch under the proving catalog:
#![allow(unused)] fn main() { let dense_output = backend.commit( dense_scheme.schedules(), &backend.import_source(dense_polynomials)?, GroupContext::scheduler_without_precommitted_groups(), )?; let prior = PrecommittedGroupProfiles::from_profiles(vec![ dense_output.committed_group.profile.clone(), ])?; let final_output = backend.commit( onehot_scheme.schedules(), &backend.import_source(onehot_polynomials)?, GroupContext::scheduler_with_precommitted_groups(&prior), )?; }
The catalog passed to commit is the producer contract for that group: it
fixes the commit profile and the source class and coefficient bound that
admission enforces. The handle records that contract, and
CommitmentHandleMetadata::producer_contract returns it. Opening data built
with SelectedProverOpeningData::from_committed_claims::<Cfg> rejects a final
group whose recorded contract differs from Cfg::committed_source_contract(),
since the proving catalog plans its final group under that contract.
Schedule rows carry no producer identity for precommitted groups, so opening
does not check them. The application must commit each precommitted group under
the configuration whose contract the proving catalog's row assumes for that
group, and it can compare each handle's producer_contract() with the contract
it planned. A mismatch cannot make a false claim verify, since the verifier
enforces the row's frozen caps. The proof's completeness and grinding budget,
however, no longer follow from the planner's model, so an honest proof can
fail. Proof bytes do not bind the producer contract.
The setup must cover every family that commits on the backend. When the proving catalog's rows already include each precommitted profile, its own setup suffices. Otherwise build the setup from combined requirements, as in Share one setup across families.
A handle from another backend is rejected during admission. When transferring
an existing commitment deliberately, use backend.import_commitment(&handle).
The receiving backend checks the source and commitment material against its
own setup before issuing a fresh handle owned by that backend.
Explicit commitment parameters
Normal applications use trusted catalog selection. A caller that already owns
a reviewed commit profile may use GroupContext::explicit(&profile).
Explicit mode commits the supplied GroupCommitPhaseParams. The opening
schedule validates its compatibility when the commitment is consumed. Use
explicit mode when the application owns the reviewed parameter distribution.
What the verifier receives
The verifier rebuilds the same ordered claims with borrowed commitments and joins them to the public schedule selection:
#![allow(unused)] fn main() { let statement = GroupBatchStatement::new( selection, OpeningClaims::from_groups(vec![ PolynomialGroupClaims::new(point, values, &committed_group)?, ])?, )?; }
The statement contains no source tables or private handles. The verifier only guide continues from this object. The proof artifacts guide explains how to carry it across a process boundary.
Setup and prepared compute state
Akita uses transparent public setup. The setup contains no secret trapdoor and needs no ceremony. A deployment can generate it from the public setup seed, store it for reuse, and derive a smaller verifier package for each supported proof shape.
The API separates protocol identity from local compute state. This lets a host cache expensive transforms without changing commitments or proof bytes.
The four setup objects
| Object | What it means | Can local copies differ? |
|---|---|---|
AkitaSetupSeed | Identity of the deterministic public matrix stream | No |
| Prover setup capacity | How much of that stream the prover materialized | Yes, if every proof requirement is covered |
| Setup prefix registry | Public commitments used by recursive setup offloading | It must cover the same supported schedules |
| Prepared backend state | Local transformed matrix prefixes and compute resources | Yes |
The public matrix stream has one identity across ring dimensions. A trusted schedule row takes the exact widths and dimensions needed by each operation from a prefix of that stream.
The current identity is Shake256PagedV1: independently derived 4096-element
SHAKE256 pages followed by exact field rejection sampling. Setup and
commitment gives the byte
encoding. A host that regenerates setup must use that versioned derivation,
not an application-specific PRG expansion of the 32-byte seed.
Build prover setup once
The normal entry point takes the largest number of variables and largest total polynomial count across the final and all precommitted groups in one opening batch that the host plans to support.
#![allow(unused)] fn main() { let catalog = TrustedScheduleCatalog::<Config>::from_artifact_bytes(&artifact_bytes, akita_params::ChunkedWitnessCfg::default_non_chunked())?; let scheme = AkitaCommitmentScheme::<Config>::new(catalog); let setup = scheme.setup_prover( max_num_vars, max_total_batched_polys, )?; }
A larger covering setup can serve a smaller proof under the same public seed. Of the setup, the commitment and proof bind only the seed, not the amount of matrix data that one prover happened to store.
For a recursive configuration, setup construction also prepares the setup prefix commitments required by its supplied catalog. The host should build setup with the configuration that will produce the final proofs.
Share one setup across families
Configurations with the same field can share one setup, and those that also share the extension field can share one backend. Compute each catalog's requirements at the same bound, combine them, and build the setup from the combined requirements:
#![allow(unused)] fn main() { let requirements = SetupRequirements::from_catalog::<DenseConfig>( dense_scheme.schedules(), max_num_vars, max_total_batched_polys, )? .union(SetupRequirements::from_catalog::<OneHotConfig>( onehot_scheme.schedules(), max_num_vars, max_total_batched_polys, )?)?; let setup = akita_pcs::new_prover_setup::<Field>(&requirements)?; }
The combined setup uses the same public seed as each per-family setup, so a proof produced with it is byte-identical to one produced with the smaller per-family setup. The transcript's instance descriptor binds the field algebra, the family's decomposition and SIS profile, the setup seed, the selected schedule row, the grinding plan, and the call layout. It binds no provisioned capacity: neither the setup's variable and polynomial bounds nor its materialized matrix length. Commitments read the same seed-derived matrix prefix under either setup. Each commitment call uses its producer catalog. Each opening selects a row from, and is admitted against, its opening catalog.
SetupRequirements<F> is tied to the field and has no public constructor
other than from_catalog and union, so every requirement passed to
new_prover_setup comes from validated catalog metadata.
Prepare the compute backend
The CPU backend turns public setup into reusable execution state.
#![allow(unused)] fn main() { let backend = std::sync::Arc::new(CpuBackend::new(setup.expanded.clone())?); }
The prepared state starts with empty transform caches. Commitment and proving kernels build exact entries as needed. A larger cached prefix can serve a smaller request with the same field, ring dimension, and transform domain.
These caches are derived from a matrix view. They are not part of the public
stream and are not covered by AkitaSetupSeed. Two machines may retain
different transform domains and prefix lengths while producing identical
commitments and proofs.
Keep the shared backend alive across repeated work. It owns prepared setup
resources and caches. Reusable commitment handles retain their immutable sources,
while every proof creates separate temporary state. Finishing or abandoning one
proof leaves other proofs and commitments valid.
Build verifier setup
The simplest conversion keeps the complete materialized public matrix prefix.
#![allow(unused)] fn main() { let verifier_setup = scheme.setup_verifier(&setup)?; }
This is a good starting point for local verification and the first integration.
A deployment that knows the exact proof schedule can derive a smaller verifier setup:
#![allow(unused)] fn main() { let resolved = scheme.schedules().resolve_selection(selection)?; let opening_layout = verifier_claims.committed_layout()?; let verifier_setup = scheme.setup_verifier_for_schedule( &setup, resolved.schedule(), &opening_layout, )?; }
The narrowed setup retains the terminal matrix and every public matrix prefix that verification still reads directly. A setup contribution carried by a recursive setup proof does not need the same direct prefix in the verifier hot path.
The complete setup prefix commitment registry remains part of verifier setup. Those commitments authenticate the offloaded public setup contributions.
Reuse and release CPU caches
Prepared state stays warm by default. That is the right policy for a service that proves many statements with the same setup.
Applications can call backend.trim_caches() to release reusable transform
entries. Active operations retain the storage they still need. Proof completion
releases proof-owned temporary state while shared caches may survive for later
proofs. Cache entries rebuild lazily when needed.
The release policy changes local memory and compute time. It does not change setup identity, commitment identity, or proof bytes. Measure the complete host before choosing it.
Disk persistence
The disk-persistence feature stores public matrix coefficients and setup
prefix artifacts. It does not store backend transform caches.
Stored setup entries include their public identity and provisioning limits. Versioned filenames prevent an older setup format from being accepted as a current entry. If a cache entry is missing or invalid, Akita can regenerate the public data from the seed.
A deployment that distributes verifier setup should authenticate the package or regenerate it from the public seed. This gives every verifier the same public setup identity while allowing each machine to choose its own local storage and compute caches.
Setup offloading
Recursive setup offloading commits to an actual power of two prefix of the public matrix stream. The prefix may be longer than the active setup weight. The extra coefficients are still real public setup data, while the weight is zero outside its natural support.
The planner chooses the commitment parameters for that prefix independently of the fold that produced or consumed it. The setup offloading chapter explains this lifecycle from planning through verifier replay.
Operational rule
Share protocol identity and choose compute state locally.
- Prover and verifier packages must agree on the setup seed and prefix commitments.
- A prover may materialize a larger covering matrix prefix.
- Each machine may build its own prepared transform caches.
- Cache release and persistence policies may follow the host's measured memory budget.
The profiling guide reports setup size and prepared cache size separately so these costs remain visible.
Proof encoding and transcripts
An Akita verification request combines proof bytes with a complete public statement. That statement contains the setup identity, commitments, opening points, claimed values, configuration, and selected trusted schedule row.
Akita binds all of these values before deriving proof challenges. This makes the public integration boundary part of the cryptographic statement.
The public proof bundle
A host should define one versioned container with these fields:
| Field | Purpose |
|---|---|
| Protocol revision | Pins the Akita proof format and transcript schedule |
| Configuration identity | Selects the field policy and expected catalog family |
| Catalog identity or storage reference | Authenticates the external schedule artifact supplied to the verifier |
| Verifier setup identity or package | Supplies the public matrix data needed for replay |
| Schedule selection | Names one exact approved catalog row |
| Ordered commitments | Fixes every polynomial group |
| Ordered opening points | States where each group is opened |
| Ordered claimed values | States one value for each committed polynomial |
| Proof bytes | Carries the canonical Spongefish argument stream |
The host may store verifier setup separately and refer to it by an authenticated identifier. The remaining values still belong to one public verification request.
Use a stable session for each protocol
The host chooses an application specific session label. Give it a version and a clear protocol owner.
#![allow(unused)] fn main() { const SESSION: &[u8] = b"my-system/akita-opening/v1"; let proof = scheme.batched_prove(&prover_setup, opening, &stacks, SESSION, basis)?; scheme.verifier(verifier_setup)?.batched_verify(&proof, SESSION, statement, basis)?; }
The verifier binds the canonical Akita instance descriptor before replay. That descriptor covers the configuration, setup identity, schedule, and public claim layout. Akita then absorbs commitments, points, claimed values, and proof messages in protocol order.
Akita constructs fresh prover and verifier states internally. Do not serialize a live state or reuse proof bytes under another session. Both sides use the same session bytes and independently bind the same public instance.
The transcript chapter lists the exact binding order and explains the wire checks used by transcript tests.
Carry the trusted row selection
SelectedProverOpeningData::selection() returns an
OpeningScheduleSelection. It names the exact row digest in the trusted catalog
used for the complete batch.
The verifier does not reconstruct a planner request from proof contents. It resolves this explicit identity in the supplied catalog, checks the row digest, and replays that schedule. This keeps planner search outside the verifier and prevents a proof from supplying its own unchecked parameters.
Store the proof canonically
The PCS returns the canonical Spongefish argument byte string.
#![allow(unused)] fn main() { let proof_bytes: Vec<u8> = proof; }
The verifier resolves the selected row from the approved catalog before it reads messages. Schedule-derived fixed counts and bounds control decoding and allocation; no proof-supplied shape is accepted.
Canonical encoding means that one accepted object has one encoding within a protocol revision. Pinning the producer and verifier to the same commit or release gives the host one proof format and transcript schedule. Upgrade both sides together and regenerate proof fixtures for the new revision.
Rebuild the statement at verification
The verifier uses borrowed commitments because it does not own prover state.
#![allow(unused)] fn main() { let claims = OpeningClaims::from_groups(vec![ PolynomialGroupClaims::new(point, values, &commitment)?, ])?; let statement = GroupBatchStatement::new(selection, claims)?; }
This constructor checks that the claim set is nonempty and structurally valid. The verifier then checks each commitment profile against the claims, setup, and resolved schedule.
Treat every incoming byte as public input
The verifier accepts public data from another process or machine. Decode it with explicit shape and size limits, build the typed statement, and pass errors back to the host.
Akita's verifier boundary returns AkitaError or SerializationError for
malformed input. This gives hosts one normal rejection path for invalid bytes,
unsupported schedules, mismatched claims, and failed cryptographic checks.
The verifier only guide puts these pieces together without the prover dependency path.
Verifier only integration
Akita provides a separate verifier package for hosts that want the smallest trusted dependency path. This package contains the public types and replay logic needed to check an approved proof schedule. Polynomial backends, commitment hints, setup generation, and planner search remain in the proving packages.
This boundary is useful for a zkVM guest, a network service, or any process that only receives proofs.
Dependencies
Pin every crate to the same Akita revision. A verifier consumer needs these packages:
[dependencies]
akita-verifier = { git = "https://github.com/LayerZero-Labs/akita", rev = "<commit>" }
akita-config = { git = "https://github.com/LayerZero-Labs/akita", rev = "<commit>", default-features = false }
akita-types = { git = "https://github.com/LayerZero-Labs/akita", rev = "<commit>", default-features = false }
akita-transcript = { git = "https://github.com/LayerZero-Labs/akita", rev = "<commit>", default-features = false }
akita-serialization = { git = "https://github.com/LayerZero-Labs/akita", rev = "<commit>" }
The default akita-verifier features enable the Blake2b transcript backend.
Schedule rows are external data, not features. The host loads approved artifact
bytes, constructs a TrustedScheduleCatalog<Cfg>, and supplies that config-bound
catalog to every verification call.
The verifier package stays small when the consumer depends only on the crates
above. The repository checks in CI that akita-verifier has no dependency on
akita-pcs, akita-prover, akita-planner, or akita-setup.
Inputs to verification
The verifier receives these public values:
- An
AkitaVerifierSetupfor the configuration and supported schedule. - The approved external schedule artifact or its validated catalog.
- A schedule selection produced with the proof.
- Ordered commitments, points, and claimed values.
- Spongefish argument bytes.
- The application transcript domain and basis mode.
The host should place them in one versioned public artifact or authenticate the setup separately. The proof artifacts guide explains the bundle.
Keep proof bytes opaque
Do not decode the proof into a host-side Rust object. Pass the argument bytes to verification; the approved schedule supplies all message counts and allocation bounds.
Commitments and verifier setup use their own canonical decoders and validation rules. Decode every public object before constructing the statement.
Build the public statement
Each group owns one point and one value for each committed polynomial.
#![allow(unused)] fn main() { let claims = OpeningClaims::from_groups(vec![ PolynomialGroupClaims::new( opening_point, claimed_values, &committed_group, )?, ])?; let statement = GroupBatchStatement::new( schedule_selection, claims, )?; }
For a multi group proof, preserve the exact order used by the prover. The final group is last, and every earlier group is a precommitted group.
Verify directly
Build one AkitaVerifier from the verifier setup and the trusted catalog, then
pass the application session label to its verification method.
#![allow(unused)] fn main() { let verifier = akita_verifier::AkitaVerifier::new(verifier_setup, catalog)?; verifier.batched_verify( &proof_bytes, TRANSCRIPT_DOMAIN, statement, BasisMode::Lagrange, )?; }
Construction fixes the catalog rows this verifier admits: those whose opening
key fits the setup descriptor and whose direct matrix uses fit the setup's
public matrix. It prepares the terminal matrix transforms of those rows once.
Verification never mutates the verifier, so one instance can serve many proofs
and threads. A verifier that checks a single proof, such as a zkVM guest, uses
AkitaVerifier::for_selection to admit and prepare only that proof's row.
The verifier resolves the explicit schedule selection in the supplied catalog. It does not run the planner. It then binds the instance descriptor, validates the public claims, and replays every fold through terminal verification.
The repository's quickstart example uses this verifier after producing and decoding a proof. Cargo compiles that call as part of the normal example checks.
Supply verifier setup
The proving environment normally creates verifier setup before packaging or serving proofs.
For a first integration, use:
#![allow(unused)] fn main() { let verifier_setup = scheme.setup_verifier(&prover_setup)?; }
For a fixed production schedule, use
setup_verifier_for_schedule. It retains only the public matrix prefix that
the selected verifier path reads directly, plus the complete setup prefix
commitment registry.
The verifier package consumes this artifact. It does not need setup generation code. A host can authenticate the package by digest, distribute it with the application, or regenerate and validate it before placing it in the verifier environment.
Handle rejection as a normal result
All verifier facing proof, setup, schedule, claim, and transcript data is
untrusted public input. The verifier returns AkitaError or
SerializationError when decoding or proof replay fails.
Match on the error at the host boundary and reject the request. Do not retry verification with another configuration or reconstructed schedule. A valid proof names one configuration, one catalog row, and one ordered public statement.
The verifier code follows a strict no panic contract for malformed public input. CI checks the dependency boundary, and the test suite exercises shape, schedule, transcript, serialization, and proof rejection paths. The verification chapter describes the full contract and the checks applied at each stage.
Verify the package boundary
Run these checks when changing a verifier integration:
scripts/check-crate-deps.sh akita-verifier
cargo clippy -p akita-verifier --all-targets --release \
--no-default-features \
--features transcript-blake2b \
-- -D warnings
The first command confirms that the verifier crate has not gained prover or planner dependencies. The second checks the narrow feature graph used by a minimal verifier build.
Operating Akita
Akita exposes its deployment choices through external schedule artifacts, explicit Cargo features, prepared compute state, and one end to end profile harness. A host loads the exact catalog it approves and measures proofs under that same catalog.
The operating path has three layers:
- Choose the feature set and load approved catalog bytes from normal storage.
- Run a complete proof workload and inspect time, memory, and proof size.
- Use focused reports or kernel benchmarks when a complete run identifies a component that needs deeper analysis.
Start with the complete build
The default akita-pcs features provide parallel CPU execution and the Blake2b
transcript backend. Schedule rows are not Cargo features and are never linked
into the binary; the first proof loads an artifact explicitly.
Use Feature flags when the host needs sequential execution, disk persistence, another transcript backend, or diagnostic instrumentation.
Measure a real proof first
Akita's profile harness runs setup, commitment, proof generation, encoding, and verification. It reports the complete public statement and the trusted schedule selected for that statement.
Start with Profiling a workload. It gives one canonical command and explains every output. This complete run shows whether a local optimization improves the time and memory of the host proof.
Read CI performance results
Profile CI compares a pull request with its merge base on the same machine. It runs dense, one hot, grouped, recursive setup, and partitioned prover cases.
Reading benchmark reports explains the public claim behind each case, the timing and memory phases, and the generated report files.
Inspect arithmetic kernels
When an end to end trace points to public matrix multiplication or transform work, use the focused NTT benchmarks. They compare ring dimensions, input widths, exact CRT paths, and available SIMD implementations without setup or transcript work.
Arithmetic microbenchmarks explains those shapes and how to interpret the 50 bit AVX-512 IFMA path.
Diagnose failures
Troubleshooting covers unsupported schedule requests, setup cache recovery, equality table limits, thread selection, verification rejection, and the Jolt guest path. Each entry begins with the public error or observable behavior and gives the next concrete check.
Akita treats these operating tools as part of the PCS. The same external catalog identity connects setup, proving, verification, profiling, and CI comparison.
Feature flags and build recipes
Akita uses Cargo features for transcript backends and compute support. Schedule
rows are external runtime artifacts, not Cargo features. The default
akita-pcs build is a parallel CPU configuration for ordinary use.
Default features
| Feature | What it provides |
|---|---|
parallel | Rayon execution across field arithmetic, setup, proving, sumcheck, and verification |
transcript-blake2b | The default Spongefish transcript backend |
The normal build uses both:
cargo build -p akita-pcs --release
Common build recipes
Sequential CPU build
Keep the default transcript while removing Rayon:
cargo build -p akita-pcs --release \
--no-default-features \
--features transcript-blake2b
This build produces the same protocol results. It changes local execution and performance.
Schedule families
Choosing fp128::DenseBounded, RecursiveCommitmentConfig<_>, or a multi-chunk
preset does not change the feature graph. Load the matching .aks artifact from
application-owned storage and pass its bytes to
AkitaCommitmentScheme::from_schedule_artifact. The config validates the family
name and planner-policy digest before any row can be used.
Disk backed public setup
cargo build -p akita-pcs --release --features disk-persistence
This stores public matrix coefficients and setup prefix artifacts. Prepared NTT caches remain local memory state and rebuild from the public setup.
Backend routing requires no Cargo feature; see backend routing.
Transcript backends
Production builds enable exactly one transcript backend.
| Feature | Backend |
|---|---|
transcript-blake2b | Blake2b based Spongefish transcript with SHA3 support |
transcript-keccak | Keccak based Spongefish transcript |
The transcript backend is part of proof compatibility. Prover and verifier must use the same backend and protocol revision.
Schedule catalog storage
Tracked development artifacts live under artifacts/schedules/. Production
applications may use a filesystem, database, object store, or another trusted
parameter channel; Akita itself accepts bytes or a validated catalog and does
not choose that storage policy. The configuration guide
explains which family to choose.
Diagnostic features
| Feature | Purpose |
|---|---|
logging-transcript | Records transcript schedule events and checks that wire values are absorbed before challenges |
response-model-diagnostics | Measures complete source and response energies for planner model calibration |
response-model-diagnostics scans witness data that normal proving does not
scan. Use it for model calibration runs, not for ordinary performance numbers.
The transcript_schedule example uses logging-transcript:
cargo run -p akita-pcs \
--features logging-transcript \
--example transcript_schedule
Profile CI features
The benchmark workflow uses narrow features such as profile-ci-fp32 and
profile-ci-distributed. Each feature compiles only the modes in one CI shard.
profile-ci is their compatibility union, and profile-bench-selected is an
internal marker used by those groups.
Application builds should treat profile CI features as repository-only mode selectors. Production schedule coverage comes from the external catalog, not the feature graph. The benchmark report guide explains how the workflow uses these selectors.
Pin one feature contract
Pin every Akita crate to the same commit or release and record the accepted feature set and approved catalog digest with the deployment. This gives the prover and verifier the same catalog identity, transcript backend, public types, and proof format.
Profiling a workload
Akita ships one profile harness for complete PCS measurements. It runs the public statement preparation, setup, commitment, proof generation, encoding, and verification needed by a real opening proof. It also records the generated schedule and proof size breakdown.
Run the canonical profile
Run this command from crates/akita-pcs:
AKITA_MODE=onehot_fp128 AKITA_NUM_VARS=36 \
cargo run --release --no-default-features \
--features parallel,profile-onehot-fp128,transcript-blake2b \
--example profile
This build contains only the adaptive fp128 one hot profile and its required protocol features. Schedule rows are loaded from the external artifact, while a narrow build keeps unrelated profile-mode monomorphizations out of the binary.
The harness requires --release. Set AKITA_ALLOW_DEBUG_PROFILE=1 only when
debugging the harness itself.
What the default statement proves
onehot_fp128 commits to one multilinear polynomial with entries and
opens it at one 36 coordinate point. The source stores one selected position in
each 256 entry chunk.
The public statement proves commitment and opening consistency. One hot is the prover representation that lets Akita skip zero work. A host constraint system can prove the one hot property separately when its application needs that claim.
The admitted row from the external schedule artifact chooses the ring dimensions for the root and every later fold. The report prints the selected sequence. The application does not choose a fixed ring dimension for this run.
Read the main phases
The profile output separates these phases:
| Phase | Work included |
|---|---|
| Statement preparation | Deterministic witness, opening point, and expected value generation |
| Setup and preparation | Public setup construction and exact retained NTT prewarming |
| Commit | Commitment to the source polynomial groups |
| Prove | Complete opening proof generation |
| Encode | Compressed proof serialization and size accounting |
| Verify | Replay with the configured multi threaded verifier pool |
| Verify with one thread | Replay of the same proof with one verifier worker |
Statement preparation belongs to the harness, not the PCS. Use the named setup, commit, prove, encode, and verify phases for protocol comparisons.
Choose the workload
| Variable | Default | Meaning |
|---|---|---|
AKITA_MODE | onehot_fp128 | Configuration and source representation |
AKITA_NUM_VARS | 32 | Number of multilinear variables; use 36 for parity measurements |
AKITA_NUM_POLYS | 1 | Number of polynomials in the final group |
AKITA_PROFILE_PROVE_THREADS | Rayon default | Prover worker count |
AKITA_PROFILE_VERIFY_THREADS | Prover count | Verifier worker count |
RAYON_NUM_THREADS | Rayon default | Fallback worker count |
The compiled binary accepts only modes enabled by its feature set. An unknown mode prints the available names.
The repository also provides dense, small field, grouped, recursive setup, and multi chunk modes. Use the narrow feature that owns the selected mode when collecting numbers for comparison.
Record a Perfetto trace
Tracing is enabled by default for the profile harness.
| Variable | Default | Purpose |
|---|---|---|
AKITA_PROFILE_TRACE | 1 | Write a Chrome and Perfetto trace |
AKITA_PROFILE_MONITOR | 1 when tracing | Record process CPU, host CPU, and memory counters |
AKITA_PROFILE_MONITOR_INTERVAL_MS | 100 | Resource sampling interval in milliseconds |
AKITA_PROFILE_LOG | trace | Console tracing filter |
AKITA_PROFILE_ANSI | 1 | Colored terminal logs |
AKITA_PROFILE_SPAN_CLOSES | 1 | Print span close events |
The trace contains counters for effective CPU cores, CPU percentage, resident memory, virtual memory, and logical CPU count. One effective core means one core was busy for the complete sampling interval.
After writing the trace, the harness writes a sibling *.summary.json. The
summary records the run identity, Git revision, exact peak resident memory,
root wall time, CPU pool use, counter statistics, and time for every span label.
Inspect it without opening Perfetto:
jq '{run, root, peak_rss_gib, cpu_utilization}' \
profile_traces/akita_nv36_onehot_fp128_*.summary.json
jq '.spans["AkitaCommitmentScheme::batched_prove"]' \
profile_traces/akita_nv36_onehot_fp128_*.summary.json
The sampled memory line shows when memory changes. The exact process high water mark records the largest resident set even when a short peak falls between samples.
Compare thread policies
Set prover and verifier counts before the process starts. Rayon fixes its global pool during initialization.
A prover value of zero lets Rayon choose. A verifier value of zero reuses the resolved prover count. A positive verifier value creates a separate pool when the counts differ. The harness prints both resolved counts.
Build without parallel to measure the same workload sequentially:
AKITA_MODE=onehot_fp128 AKITA_NUM_VARS=32 \
cargo run --release --no-default-features \
--features profile-onehot-fp128,transcript-blake2b \
--example profile
Measure response model data
Normal profile runs measure the production prover path. Response model calibration adds full witness scans, so enable it explicitly for those runs:
AKITA_MODE=onehot_fp128 AKITA_NUM_VARS=32 \
cargo run --release --no-default-features \
--features parallel,profile-onehot-fp128,transcript-blake2b,response-model-diagnostics \
--example profile
This mode records exact source and response energies, planned caps, accepted nonces, and attempt counts. Those additional scans change prover work, so keep their results separate from normal performance measurements.
Continue the analysis
- Reading benchmark reports explains the CI matrix and pull request comparison artifacts.
- Arithmetic microbenchmarks isolates NTT public matrix multiplication and SIMD paths.
- Troubleshooting explains profile startup, schedule, allocation, cache, and thread errors.
Reading benchmark reports
Akita profile CI measures complete opening proofs at several public statement shapes. Pull request runs compare the branch with its merge base on the same runner, using the same feature set and interleaved executions.
The workflow at .github/workflows/profile-bench.yml defines the current cases.
The report scripts turn those runs into a compact pull request comment and a
full downloadable artifact.
Current statement matrix
| Case | Polynomial groups | Setup path |
|---|---|---|
dense_fp32 | 1 at nv30 | Direct |
onehot_fp32 | 1 at nv34 | Direct |
dense_fp64 | 1 at nv29 | Direct |
onehot_fp64 | 1 at nv35 | Direct |
dense_fp128 | 1 at nv28 | Direct |
onehot_fp128 | 1 at nv36 | Direct and recursive |
onehot_fp128_multi_group | 1 at nv16 + 1 at nv16 + 2 at nv34 | Direct |
onehot_fp128_multi_group_recursive | 1 at nv16 + 1 at nv16 + 2 at nv34 | Recursive |
onehot_fp128_multi_group_recursive_multi_chunk_w8r2 | 1 at nv16 + 1 at nv16 + 2 at nv32 | Recursive |
onehot_fp128_multi_chunk_w2r2 | 1 at nv32 | Direct |
onehot_fp128_multi_chunk_w4r2 | 1 at nv32 | Direct |
onehot_fp128_multi_chunk_w8r2 | 1 at nv32 | Direct |
The workflow splits these cases into narrow feature groups so each runner
compiles only the profile modes it measures. Each runner loads the matching
checked-in .aks schedule artifact at runtime.
What each statement means
The dense cases commit to one arbitrary multilinear table and open it at one point. The current fp32, fp64, and fp128 cases use 30, 29, and 28 variables.
The one hot source places one selected value in every 256 entry chunk. The public statement still checks commitment and opening consistency. The source representation changes prover work, not the meaning of the opening claim.
The multi group cases contain four polynomials in three ordered groups. Two earlier groups each contain one 16 variable polynomial and use separate points. The final group contains two polynomials that share one point. It uses 34 variables in the direct and standard recursive cases. The W8R2 case uses 32 variables.
Direct and recursive rows prove the same opening statement. The recursive setup row carries the large public setup contribution through a Stage 3 sumcheck. Direct mode evaluates that contribution during Stage 2.
W2R2, W4R2, and W8R2 divide the witness relation into 2, 4, or 8 chunks during the first folds. The generated schedule may choose different A, B, and D ring dimensions at each level.
Work performed by one sample
Every measured process performs these operations:
- Generate deterministic source data, opening points, and expected values.
- Build setup and prepare retained NTT requirements.
- Commit to every polynomial group.
- Produce and serialize one complete opening proof.
- Check the reported proof size.
- Build verifier setup.
- Verify with the configured worker pool.
- Verify the same proof again with one worker.
Each sample runs in a fresh process. Setup is built in memory, and profile CI does not enable disk persistence.
How the comparison works
Pull request runs compare with the merge base, not the current tip of main.
The workflow builds both revisions and runs them on the same machine. It
interleaves the two binaries so changes in runner load affect them as evenly as
possible.
Each case has one discarded warmup process and three measured processes. The report uses the median time and the largest peak resident memory. A negative delta means that the branch used less time, memory, or proof data.
The x86 runners compile for the fixed x86-64-v3 target. This keeps the
instruction set stable across machines while retaining AVX2. CPU fingerprints
are recorded with the artifacts.
Compact pull request comment
The compact comment begins with the public statements. It then separates:
- Phase time.
- Peak memory and setup size.
- Proof size.
- The resolved A, B, and D dimension sequence.
Consecutive repeated dimension tuples are collapsed. This keeps the comment readable while still showing a schedule change.
Failed cases remain visible and name the phase that failed. A missing or unsupported merge base mode is reported instead of being compared with a different workload.
Full report artifact
scripts/profile_bench_report.py writes these files:
| File | Use |
|---|---|
summary.json | Complete machine readable result |
summary.csv | Flat data for analysis tools |
report.md | Detailed human readable report |
| Pull request comment | Compact branch versus merge base summary |
The detailed report shows every fold. Each fold records matrix geometry, decomposition, challenge parameters, witness or setup input, relation geometry, and proof components. Multi group rows repeat these blocks for each group instead of joining unrelated values.
The report also names the opening method for each group. A coefficient packing row includes its challenge subring dimension, packing factor, partial width, and packed field width. These fields explain a time or setup difference that a single ring dimension cannot explain.
Interpreting setup and cache numbers
Setup and preparation includes exact NTT prewarming for the selected commit
and prove schedule. The retention policy skips large ring switch requirements
that the runtime streams.
The harness checks that retained shared matrix cache entries do not grow during commit or prove. As a result, these phases measure warm retained entries plus intentional streamed work.
Prepared NTT cache size reports the retained shared matrix footprint at the
prewarm boundary. Compression cache entries are built by their operations and
are not included in that line. CpuPreparedSetup::ntt_cache_bytes reports the
complete resident cache when an application needs that number.
Dense statement preparation appears in traces but is excluded from protocol phase comparisons. It includes deterministic evaluation generation and the independent expected opening calculation.
Keep reports tied to public claims
A performance number is useful only with its complete statement, schedule, feature set, thread policy, and Git revision. The Akita report preserves these facts so a proof size or timing change can be traced to the protocol choice that caused it.
Use Profiling a workload to reproduce one case locally. Use Arithmetic microbenchmarks when the report points to NTT public matrix multiplication as the next target.
Arithmetic microbenchmarks
Akita's complete profile is the main performance measure. Focused arithmetic benchmarks answer a narrower question after that profile identifies a hot kernel.
The ntt_matvec Criterion target measures public matrix multiplication without
setup construction, transcript work, planning, or the rest of the proof.
Run the benchmark groups
cargo bench -p akita-cpu-backend --bench ntt_matvec -- rank_ring_dim
cargo bench -p akita-cpu-backend --bench ntt_matvec -- width
cargo bench -p akita-cpu-backend --bench ntt_matvec -- equal_output
cargo bench -p akita-cpu-backend --bench ntt_matvec -- equal_io
Use a shape filter for one quick comparison:
cargo bench -p akita-cpu-backend --bench ntt_matvec -- d64_r4_w128
Prepared cache construction is outside the timed region. The measurement includes digit validation, forward transforms, pointwise accumulation, inverse transforms, CRT reconstruction, and output allocation.
Compared kernels
Every common shape includes the production i8 commitment path and the unified i16 path. The i16 cases cover digit bases L2 through L11 where supported. The label states whether exact reconstruction uses only the base CRT residues or also needs the optional i16 tail.
On an x86 host with AVX-512IFMA, eligible labels also include ifma52. This
path stores canonical 50 bit prime residues in u64 lanes and uses the IFMA52
instructions for exact arithmetic.
The label applies only to the selected exact i16 cache and kernel. The ordinary i32 NTT still dispatches to AVX2 on x86. The benchmark names these paths separately so an IFMA result cannot be mistaken for a global NTT backend change.
Ring dimension and rank sweep
The rank_ring_dim group tests ring dimensions 64, 128, 256, and 512. At each
dimension it tests output ranks 1, 2, 4, and 8 with ring width 128.
This sweep changes both the scalar input size and the ring structure. Use it to see which dimensions are competitive for a specific matrix geometry, not to claim that a larger ring is always faster.
Width sweep
The width group tests widths 128 through 1024 at ring dimension 64 and rank 4.
It shows how the kernel scales as the number of input ring columns grows.
Equal output and equal input cases
The equal_output group compares these shapes:
D64 rank 8
D128 rank 4
D256 rank 2
D512 rank 1
Each shape returns 512 field coefficients. Its scalar input size still grows with the ring dimension.
The equal_io group also adjusts the width:
D64 rank 8 width 1024
D128 rank 4 width 512
D256 rank 2 width 256
D512 rank 1 width 128
These shapes hold both scalar input and output sizes fixed. This isolates the trade between ring structure, transform cost, and available parallel work.
Understand the scaling
Let n = width * D be the scalar input length and m = rank * D be the scalar
output length. An ordinary dense matrix multiplication costs O(m * n).
Akita stores the matrix as rank * width negacyclic ring blocks. With a
prepared matrix, the approximate work for each CRT residue is:
input transforms: n * log D
pointwise products: m * n / D
output transforms: m * log D
The ring structure divides the pointwise term by D. Larger rings also reduce
prepared matrix storage for a fixed scalar input and output shape.
Transform work grows with log D. Exact CRT bounds also grow with D, and a
shape with fewer ring rows may expose less parallel work. The generated planner
therefore chooses dimensions from measured and certified candidates instead of
always choosing the largest ring.
Return to the complete proof
Criterion throughput counts rank * width * D coefficient products. The
complete profile adds setup, commitment assembly, sumcheck, transcript work,
proof encoding, and verification.
After a kernel change, run the matching complete mode from Profiling a workload. The end to end result decides whether the change improves Akita for its host application.
Troubleshooting
This page covers failures that can occur before or around a proof run. When an error comes from verification, first read Verifier only integration and the verifier no-panic contract.
The profile example exits before running
The profile example requires a release build because debug timings are not
useful. If it prints this message, add --release to the Cargo command.
examples/profile must be run with --release for meaningful timings.
Set AKITA_ALLOW_DEBUG_PROFILE=1 only when you need to debug the harness. Do
not compare timings from that run with release results.
An unknown AKITA_MODE also stops the process. The error lists the modes that
were compiled into the current binary. A build with a narrow feature set can
contain only one profile family, so use the matching mode and feature. See
Profiling for the canonical command and Feature
flags for the available profile modes.
The requested schedule is unsupported
AkitaError::UnsupportedSchedule means the catalog supplied to the scheme does
not contain a row for the exact request. Runtime code does not invoke the
planner to fill a missing row.
Check these causes in order:
- Confirm that the application loaded the intended family artifact and that its catalog identity matches the setup or preprocessing package.
- Confirm that the chosen preset supports the requested polynomial arity, group shape, and opening method.
- For a recursive grouped opening, commit each precommitted group with the base configuration. Use the recursive configuration for the final grouped commitment and proof.
- If the request should be supported, record the complete error text and the
exact configuration,
num_vars, polynomial counts, and ordered group layout. A catalog row may need to be generated and shipped.
See Configuration and planning for catalog ownership and Recursive grouped openings for the grouped setup pattern.
Equality table allocation is rejected
Akita checks each materialized equality table allocation against a 1 GiB
budget. A request over that limit returns AkitaError::InvalidInput before
the allocation. The message includes the table label, element count, byte
count, limit, and source location.
Lower num_vars when testing a workload that does not need the larger domain.
For a production request, keep the complete error and configuration details.
Some protocol paths use split equality weights and do not materialize the full
table. Do not raise the limit as a first fix. It is an allocation safety
boundary, not a tuning knob.
This check covers equality tables only. The witness, setup matrix, retained NTT entries, and proof workspace use additional memory. Use the RSS counters and summary described in Profiling to locate the phase where memory grows.
A setup cache cannot be loaded or saved
The disk-persistence feature stores the public setup matrix and setup prefix
registry. It does not store backend NTT caches.
Cache entries use versioned filenames, and prefix registry names include a digest of the setup requirements: the capacity bound and the sorted setup prefix slot ids. Old, truncated, corrupt, or mismatched entries are not accepted as current setup. Akita logs the load failure and regenerates the setup. If saving the replacement fails, Akita logs a warning and continues with the in-memory setup.
Akita chooses the cache directory from environment variables in this order:
- If
LOCALAPPDATAis set, use$LOCALAPPDATA/akita. - Otherwise, if
HOME/Library/Cachesexists, use$HOME/Library/Caches/akita. - Otherwise, if
HOMEis set, use$HOME/.cache/akita.
This order is independent of the operating system. If neither environment variable is set, disk persistence has no cache path.
Normal upgrades do not require manual cache deletion. If every run reports a
write failure, check that the directory is writable or build without
disk-persistence. If every run rejects a newly written entry, preserve the
warning and affected cache file for diagnosis before removing that file.
Thread counts do not match the profile request
The profile harness reads AKITA_PROFILE_PROVE_THREADS and
AKITA_PROFILE_VERIFY_THREADS. Each value falls back to RAYON_NUM_THREADS
when it is missing or invalid. The prover pool resolves first. A prover value
of 0 lets Rayon choose the global pool size. A verifier value of 0 reuses
that resolved prover size. A positive verifier value creates a separate pool
only when it differs from the prover size. The harness prints both resolved
counts at startup.
Set the profile variables before the process starts. Rayon global pool size is
fixed during initialization. When the parallel feature is disabled, prover
and verifier work is sequential and all reported thread counts are one.
Verification rejects an artifact
A verifier error does not always mean the proof was wrong. Decode and shape
errors mean the public artifact was malformed. A statement that does not fit
the verifier's setup or the selected schedule row returns the failing check's
own error before transcript replay starts: InvalidSize or
InvalidPointDimension for a statement larger than the setup, and
InvalidInput with a message for a claim group or commitment profile that
does not match. AkitaError::InvalidProof means the proof bytes failed a
protocol check.
Confirm that prover and verifier use the same Akita revision, configuration, transcript backend, transcript domain, ordered commitment groups, opening points, and claimed evaluations. Akita does not preserve proof bytes across revisions. Regenerate the proof and verifier setup after an upgrade.
Akita reports an internal error
AkitaError::Internal means an invariant that Akita maintains itself failed
after the inputs were accepted. The cause is a bug in Akita or in a custom
backend. It is not a problem with the request, the setup, or a proof. The
message names the failed invariant. Report it with the complete error text and
the configuration that produced it.
Verification can report this error too, and it still means a bug rather than a rejected proof.
A Jolt recursion run fails
The Jolt host performs strict native decoding and Akita verification before it starts guest preprocessing. Fix that preflight error first.
The guest output has three defined values:
| Value | Meaning |
|---|---|
0 | Akita verification succeeded |
1 | Input decoding or statement construction failed |
2 | The Akita verifier rejected the proof |
A guest panic is reported separately as guest_panic. Start a new schedule or
larger arity with --trace-only and confirm that it fits the guest trace limit
before running the full Jolt prover.
For a panic, temporarily change the guest attribute to
backtrace = "dwarf", rebuild the guest, and run with
JOLT_BACKTRACE=full. The exact commands, cache paths, memory limits, and
current trace limit live in the
profile/akita-recursion runbook.
What to include in a bug report
Include the full error, Akita commit, Cargo feature set, configuration type,
ordered group layout, num_vars, polynomial counts, operating system, CPU
architecture, and resolved thread counts. For performance or memory failures,
also include the profile summary JSON and the command that produced it. Do not
attach private witness data or application inputs.
Integrating with a proof system
Akita is a standalone polynomial commitment scheme. It can serve any proof system that works with polynomial evaluation tables and can state the values it wants to open. The host system does not need to adopt Akita's internal ring arithmetic or proof planner. It needs a small adapter that translates its own polynomials and claims into Akita's public interface.
This chapter describes that adapter. The Jolt recursion chapter then shows a complete integration in which a zkVM executes the Akita verifier.
What the adapter owns
The host system owns the meaning of the committed data. It may be a virtual machine trace, a lookup table, a memory-checking polynomial, or another value used by the host protocol. Akita sees an ordered collection of polynomial tables and opening claims.
The adapter joins these two views.
| Host concern | Adapter decision | Akita input |
|---|---|---|
| Which values are committed | Preserve the host's canonical order | Dense or one hot polynomial sources |
| Which field holds those values | Select the matching Akita configuration | CommitmentConfig |
| Which claims belong together | Group polynomials by arity and opening point | OpeningClaims |
| Which public statement is proved | Preserve commitments, points, values, and group order | GroupBatchStatement |
| Which protocol session owns the proof | Choose stable versioned session bytes | &[u8] session |
| What crosses the prover boundary | Define a versioned public bundle | Setup, schedule selection, claims, and proof |
This is the main design rule: keep the host meaning outside Akita, but make the translation into Akita explicit and deterministic. The prover and verifier must construct the same ordered statement from the same public host data.
Start from the host's polynomial model
Akita's current API opens multilinear polynomials. A multilinear polynomial in variables is represented by its values on Boolean inputs. Many proof systems already store trace columns and lookup tables in this form.
For each host polynomial, record:
- Its field.
- Its number of variables.
- Its table representation.
- The point where the host protocol opens it.
- The position of its claimed value in the host transcript.
Use DensePolynomial for a general evaluation table. Use OneHotPoly when the
host already has one selected value in each fixed size chunk. Keeping one hot
data structured avoids building a large dense table only to recover the same
sparsity inside the prover.
Polynomials with the same arity can share a commitment group. Polynomials in one opening group also share one opening point. If the host opens different groups at different points, preserve those groups and their order. Akita can batch them into one proof.
Select the field boundary once
Choose one Akita configuration whose base field matches the values supplied by the host. Keep conversion code at the adapter boundary. A field element should enter Akita through one canonical conversion and leave through one canonical encoding.
Do not convert values by copying their in-memory bytes. Rust field types can use different internal representations even when they describe the same prime field. Convert through canonical integers or an agreed canonical byte encoding, then test the boundary with zero, one, the largest canonical value, and random values.
The configuration guide explains the shipped dense and one hot configurations. Akita chooses the ring dimensions and fold schedule after the adapter supplies the field and claim shape.
Build one public statement
The host should define a single versioned Akita artifact. It contains, or securely identifies, everything the verifier needs:
- the Akita revision and configuration;
- the verifier setup;
- the exact generated schedule selection;
- the ordered commitments;
- the ordered opening points and claimed values;
- the proof bytes;
- the session bytes used by this host protocol.
This bundle is more than a transport format. It is the complete public claim. The verifier should not infer missing group order, try several configurations, or choose a schedule after receiving the proof.
Use session bytes owned by the host, such as
my-system/trace-openings/v1. A versioned label separates this proof from every
other Akita use and gives the host a clean protocol upgrade boundary.
The proof encoding and transcripts chapter gives the exact Akita objects and decoding flow.
Place the verifier where it provides the most value
Akita's verifier is a separate Rust package. A host can place it in several environments:
| Verifier placement | Typical use |
|---|---|
| In the host process | Check locally generated proofs and network requests |
| In a dedicated service | Keep proving and verification deployments separate |
| In a zkVM guest | Prove that the Akita verifier accepted a proof |
| In another recursive circuit | Compress or aggregate Akita verification with other claims |
The direct akita-verifier path has no polynomial backend, setup generator, or
planner search. This makes it the right boundary for small verifier targets.
The host decodes the public bundle, reconstructs the typed statement, starts a
fresh verifier transcript, and calls AkitaVerifier::batched_verify.
When the verifier itself runs inside another proof system, begin with native verification of the same bundle. Then move the exact accepted bundle into the guest or circuit. This gives the integration a simple debugging order:
host creates Akita proof
↓
native Akita verifier accepts it
↓
guest or circuit decodes the same public bundle
↓
guest or circuit runs the Akita verifier
↓
outer proof system proves that execution
The native check separates an Akita statement error from a guest runtime or outer prover error.
Plan setup and upgrades as deployment inputs
The proving service prepares the large reusable compute state. The verifier receives only the public setup needed by its selected schedule. A deployment can package this setup with the verifier or authenticate it by an application owned identifier.
Pin every Akita crate to one revision. Akita's protocol and proof encoding can advance together, so treat an upgrade as a new host artifact version. Rebuild setup packages, regenerate proof fixtures, and run the complete host-to-verifier path before deploying the new version.
Validate the integration at its real scale
A useful integration test covers more than one successful proof. It should:
- Compare host and Akita field conversions in both directions.
- Compare each claimed value with an independent host evaluation.
- Round trip the complete public artifact through serialization.
- Accept a valid proof through the final verifier entry point.
- Reject changed commitments, points, values, schedules, and proof bytes.
- Measure proving time, peak memory, verifier time, and proof size at the host's intended polynomial sizes.
For a zkVM or recursive circuit, also measure input decoding separately from Akita verification. A large verifier setup can make transport and decoding the dominant cost even when the verifier kernel is fast.
The repository's Jolt harness follows this pattern. It produces a real Akita proof, checks it natively, transports one bounded verifier bundle into a RISC-V guest, runs the direct verifier there, and measures each phase.
Jolt recursion
Jolt is a zero-knowledge virtual machine that proves the correct execution of 64-bit RISC-V programs. Akita's Jolt integration turns the Akita verifier into one of those programs. Jolt can therefore produce an outer proof that says an Akita opening proof was accepted.
This is recursive verification: one proof system proves the execution of another proof system's verifier. It lets a host combine Akita's compact, post-quantum polynomial commitments with the execution and composition tools provided by a zkVM.
The live integration is the standalone workspace under
profile/akita-recursion/. Its
runbook
contains current commands, environment variables, and measured trace notes.
The complete path
The integration has four small crates.
| Crate | Runs where | Responsibility |
|---|---|---|
artifact | Native host | Creates a real Akita commitment, opening proof, and verifier bundle |
glue | Host and guest | Defines the bounded AkitaJoltInputs wire format |
guest | Jolt RISC-V guest | Decodes the bundle and calls AkitaVerifier::batched_verify |
host | Native host | Compiles the guest, runs Jolt, and checks the outer proof |
The data flow is direct:
Akita artifact generator
│
│ AkitaJoltInputs bytes
▼
strict native Akita verification
│
▼
Jolt RISC-V guest
│ decode input
│ rebuild statement
│ run Akita verifier
▼
guest result: accepted or rejected
│
▼
Jolt proves and verifies the guest execution
Before compiling or proving the guest, the host strictly decodes the bundle and runs the native Akita verifier. This makes failures easy to locate. If the native check fails, the public statement or Akita proof is wrong. If it passes, the remaining work belongs to guest compilation, execution, or the Jolt prover.
What crosses into the guest
AkitaJoltInputs<F, D> is one versioned verifier bundle. It contains:
- the transcript domain;
- the polynomial arity and opening point;
- the claimed value and commitment;
- the exact generated schedule selection;
- the verifier setup;
- the canonical native Akita proof bytes.
The decoder checks a format marker, the fixed source-view dimension, bounded lengths, complete consumption of the input, and a schedule-derived upper bound on the proof stream before allocation. The guest then rebuilds the same opening statement used by the native verifier.
The guest depends on akita-verifier rather than the complete PCS package. It
does not carry the polynomial backend, setup generator, or planner into the
RISC-V program.
The current configuration
The harness uses proof_optimized::fp128::OneHot. Its input is one structured
one hot polynomial, and the guest is compiled with a source-view dimension of
. This fixed type is the root envelope for the current adaptive
configuration. The generated schedule still chooses the dimensions used at
each later fold.
AKITA_NUM_VARS chooses the polynomial arity. The artifact generator resolves
the approved row for that exact arity and rejects a row that does not match the
guest's fixed source view. The default is 20 variables. The 32 variable target
uses the same source view and is the large recursion benchmark.
The recursion workspace is separate from the main Cargo workspace. It pins Rust 1.95, the RISC-V targets, and one exact Jolt revision. This keeps Jolt's toolchain and patched dependencies out of the main Akita dependency graph.
Run the native artifact and guest trace
Install the Jolt CLI from the same revision pinned by the recursion workspace.
Then run these commands from profile/akita-recursion/:
cargo build --release
AKITA_NUM_VARS=20 \
./target/release/akita-recursion-artifact
ZEROOS_GUEST_RUSTFLAGS=-Zunstable-options \
AKITA_RECURSION_LOG=info \
./target/release/akita-recursion-host \
--trace-only \
--trace-output /dev/null
The artifact command proves and verifies natively before publishing the input blob. The trace command compiles and executes the guest without running the full Jolt prover. It is the fastest way to confirm that a new Akita revision or larger arity fits the guest.
The guest reports three cycle regions:
| Marker | Work measured |
|---|---|
deserialize_input | Decode and validate the verifier bundle |
prepare_verifier | Admit the selected row and install or prepare its terminal matrix |
akita_verify | Build the public statement and run the Akita verifier |
At large arities, decoding the expanded verifier setup can dominate the guest trace. Measuring it separately makes that transport cost visible instead of attributing it to the Akita verifier.
Run the full recursive proof
Begin with the 20 variable target, whose trace fits the guest's current instruction limit:
AKITA_NUM_VARS=20 ./target/release/akita-recursion-artifact
ZEROOS_GUEST_RUSTFLAGS=-Zunstable-options \
AKITA_RECURSION_LOG=info \
./target/release/akita-recursion-host \
--input target/akita_recursion_inputs.bin
The full command performs Jolt preprocessing, proves the guest execution, and
verifies the resulting Jolt proof. Success ends with
Akita-in-Jolt proof OK, is_valid=true, and guest_panic=false.
The 32 variable target is intended for a server with enough memory for its
large input and trace. Measure it with --trace-only first. The current
follow-up is to record its adaptive trace length and raise Jolt's trace limit
if that measured execution exceeds instructions.
Rejection is part of the proved execution
The guest returns a small status value:
| Value | Meaning |
|---|---|
0 | Akita verification succeeded |
1 | Input decoding or statement construction failed |
2 | The Akita verifier rejected the proof |
Malformed public input produces a defined nonzero guest result. Jolt proves that result in the same way it proves a successful result. A guest panic is reported separately.
Trusted benchmark setup
The host always performs strict setup decoding and Akita verification before the guest runs. For cycle measurement, the RISC-V benchmark guest then uses the already checked expanded setup matrix directly. This keeps the benchmark focused on transport and verifier execution.
A deployment can preserve the same trust boundary by authenticating the setup package outside the guest. A deployment that receives setup from an untrusted source should use strict setup decoding inside the guest. The normal guest feature keeps strict decoding enabled; the host opts into the benchmark path only for the ELF it builds through the pinned Jolt SDK.
Keep the integration current
The smoke workflow compiles and tests the glue, artifact, and host against the current Akita APIs. It does not run the expensive Jolt trace or proof. After an Akita or Jolt upgrade:
- Run the recursion workspace tests and release build.
- Generate a fresh artifact and confirm native verification.
- Run
--trace-onlyand compare the three cycle markers. - Run the full Jolt proof at a known arity.
- Measure the intended production arity on its deployment class machine.
Pin the complete integration to one Akita revision. Regenerate the verifier bundle after every protocol upgrade because setup, schedule identity, proof shape, and proof encoding advance together.
How it works
Akita opens a committed polynomial by repeatedly replacing a large hidden table with a new committed witness. Every replacement comes with a proof that the new witness carries the same opening claim and satisfies the required commitment relations. The last witness is small enough for the verifier to check directly.
That repeated reduction is the central idea behind the implementation. The configuration decides the exact sequence of folds. The prover executes it. The verifier derives the same sequence from public inputs and rejects any proof whose shape or messages do not match.
This part of the Book explains that path from public configuration to final acceptance. It is for contributors, integrators who need to understand the proof boundary, and reviewers who want to connect each protocol claim to the code that enforces it.
The same batched_prove and batched_verify APIs always use a folded schedule.
Every schedule contains a root fold and a terminal cleartext witness, with zero
or more recursive folds between them. The root may connect directly to the
terminal witness when no recursive fold is needed. Schedule selection rejects
a request when the audited fold domain contains no valid complete schedule.
The complete proof in one view
An Akita opening moves through the following stages.
- Resolve the schedule. The selected
CommitmentConfigmaps the workload shape to one generated schedule row. That row fixes every fold, matrix dimension, decomposition basis, opening method, and terminal profile. - Prepare the setup and commitments. The prover materializes the required prefix of the public setup. Each polynomial group is committed with the parameters assigned to that group.
- Bind the public statement. The transcript absorbs the configuration, setup identity, schedule, commitment groups, opening points, and claimed evaluations before deriving challenges that depend on them.
- Run the root fold. The prover prepares each requested opening, builds the first fold relation, and proves that relation with the scheduled sum-checks. The fold emits a recursive digit witness and a new opening claim; the root witness need not be smaller than its input.
- Run any recursive folds. Each nonterminal successor authenticates the witness produced by its predecessor and repeats the same reduction. A fold may also authenticate a prepared setup prefix when setup offloading was selected.
- Check the terminal witness. The final witness is sent in clear encoded form. The verifier checks its consistency, commitment relation, evaluation trace, and any scheduled norm bound directly. There is no further recursive commitment and no terminal sum-check cascade.
The verifier performs the same steps in the same transcript order. It does not trust the proof to choose a schedule or describe its own lengths. Public configuration and claims determine the expected shape before proof data is decoded.
polynomial groups + opening claims
|
v
generated root schedule
|
v
root relation and fold
|
v
next committed digit witness
|
zero or more recursive folds
|
v
clear terminal witness check
|
v
accept
What one fold preserves
A fold reduces the current relations to a recursive opening claim without weakening their connection to the committed source. The full next-level witness includes auxiliary and representation data, so its physical size is not guaranteed to decrease at every fold. In particular, root folds may be non-contractive. Akita maintains three invariants at every nonterminal level.
The opening claim remains attached to the witness
The current level starts with one or more claims that committed polynomials evaluate to stated values at stated points. Its relation turns those claims into one evaluation of the next witness. That value becomes the opening claim consumed by the successor.
Multiple commitment groups may enter the root together. Each group keeps its own commitment, point, values, and parameters. The root batches their checks, then returns to the ordinary recursive path with one folded witness.
The commitment relations remain binding
The prover cannot choose an arbitrary successor witness. Each fold proves the relations that connect source digits, inner commitment values, outer commitments, opening digits, and the folded response. The proof may carry raw commitment values or smaller compressed payloads, but both forms enforce the same semantic commitment statements.
Every size and method comes from the schedule
The schedule owns the ring dimensions for the A, B, and D matrix roles, the number of blocks, the digit bases, the opening method, the proof shape, and the terminal policy. Prover and verifier consume these values through the same typed schedule structures. Unsupported geometry fails during schedule resolution or validation rather than selecting an improvised protocol.
The main branches in the protocol
The fold engine is shared, but a generated schedule can select among several well-defined paths.
| Choice | What changes | Where to read |
|---|---|---|
| Coefficient packing or evaluation trace | How an extension-valued opening is represented in the fold relation | Fold path and field geometry |
| Raw or compressed commitment payload | Which commitment values appear on the wire and which extra physical rows are proved | Raw and compressed realizations |
| Direct or offloaded setup contribution | Whether the verifier scans setup now or a later fold authenticates a prepared setup prefix | Setup offloading |
| Coefficient or Euclidean response bound | Which range and norm checks certify the folded response | Security model and Sum-check stages |
| Dense or one-hot source | How the prover computes the commitment and source operations | Setup and commitment |
These choices are not independent switches supplied by a proof. The generated schedule contains one complete compatible assignment.
Read this section by goal
Understand the system first
Read these chapters in order:
- Architecture overview for crate ownership and the
public
commit,prove, andverifylifecycle. - Configuration and planning for the generated schedule and the difference between offline search and runtime resolution.
- Setup and commitment for the public matrices and Ajtai commitment.
- The proving protocol for one fold from input claim to successor witness.
- Verification for transcript replay, final checks, and malformed-input rejection.
Implement or review a proof stage
Start with The proving protocol, then follow its links to the relation, layout, and sum-check chapter for the stage being changed. Pair the prover path with the matching page under Verification. The protocol is complete only when both sides compute the same claim from the same ordered messages.
Review security boundaries
Read Transcript and instance binding, Verification, and Security model. Then trace each accepted norm bound and matrix role back to the generated schedule and Module-SIS tables. The useful review question is not merely whether an equation appears in the prover. It is whether the verifier derives and enforces every public condition needed by that equation.
Review performance
Read Optimizations after the protocol path is clear. The fast implementation changes table representations, arithmetic kernels, and execution order. It does not define a second proof system. Scalar references, schedule checks, and verifier equations remain the correctness boundary.
Chapter map
| Chapter | Main question |
|---|---|
| Architecture overview | Which crate owns each concept, and how do the public calls flow through them? |
| Configuration and planning | How does one public workload select an exact generated schedule? |
| Setup and commitment | How do public matrices bind a polynomial group? |
| Transcript and instance binding | Which public facts are absorbed before each Fiat-Shamir challenge? |
| The proving protocol | How does one nonterminal fold create and authenticate its successor witness? |
| The distributed prover | Which fold computations can remain local to independent machines? |
| Recursion and proof shape | How are root, recursive, and terminal records connected? |
| Setup offloading | How can a prepared setup commitment replace a large online verifier scan? |
| Verification | How does the verifier replay every level and reject malformed input without panicking? |
| Security model | Which assumptions, norm regimes, and generated bounds support acceptance? |
| Optimizations | How does the implementation make the same protocol fast? |
Where the lifecycle enters the code
The public orchestration lives in crates/akita-pcs/src/scheme/. The prover
walk begins in crates/akita-prover/src/protocol/prove/root.rs. The verifier
mirror begins in crates/akita-verifier/src/fold/verify.rs.
Those files should remain orchestration layers. Mathematical rules belong to their canonical layout, algebra, schedule, sum-check, or verifier helpers. A reviewer should be able to follow the lifecycle here, enter one of those three paths, and find one implementation owner for every rule.
Architecture overview
How the workspace is organized and how a single commit → prove → verify call
flows through it.
Crate map
Workspace members live under crates/.
There is no akita-scheme crate: end-to-end AkitaCommitmentScheme
orchestration lives in akita-pcs.
| Crate | Role |
|---|---|
akita-error | Shared protocol error and reusable checked integer formulas for exact sizes, offsets, and ranges |
jolt-field (external) | Shared field traits, prime and extension fields, packed and unreduced kernels, parallel helpers |
akita-serialization | Serialization, validation, and compression traits |
akita-algebra | Modules, vectors, NTTs, cyclotomic rings, sparse challenges, polynomials |
akita-transcript | Spongefish-backed Fiat-Shamir transcript, descriptor preamble, logging checks |
akita-challenges | Fiat-Shamir challenge sampling helpers |
akita-sumcheck | Sumcheck proofs, drivers, compact folding, batching, accumulation |
akita-params | Parameter geometry, sizing, SIS tables, schedules, compression plans, witness layout, dispatch, and grinding plans |
akita-types | Proof, setup, and claim wire values, shared protocol math, and native transcript replay |
akita-planner | Cfg-free offline schedule search and artifact emission |
akita-schedules | Versioned schedule artifacts, semantic row audit, and validated owned catalogs |
akita-config | Runtime presets, the CommitmentConfig trait, trusted artifact loading, policy_of::<Cfg>(chunking), and transcript binding |
akita-setup | Config-backed setup construction and optional setup cache |
akita-verifier | Verifier replay without prover-only polynomial backends; directly <Cfg>-generic |
akita-prover | Protocol sequencing, public geometry checks, proof assembly, opaque operation contracts |
akita-cpu-backend | Backend-owned sources, commitment and witness arithmetic, prepared setup resources, caches |
akita-pcs | Umbrella crate: AkitaCommitmentScheme, re-exports, examples, benches, integration tests |
Dependency graph and ownership rules: docs/crate-graph.md.
CI enforces one-way boundaries via scripts/check-crate-deps.sh.
Key structural facts:
akita-erroris the lowest shared failure layer. It ownsAkitaErrorand reusable exactusizeformulas inakita_error::checked. These formulas returnOption; each caller maps failure to theAkitaErrorvariant that describes its protocol boundary. Field arithmetic lives in the shared externaljolt-fieldcrate.akita-plannerowns offline schedule search and artifact emission. Normal search isCfg-free and is not on the verifier runtime dependency path. The optionalcatalog-genfeature enablesakita-config, so artifact-emission binaries may name concreteCommitmentConfigpresets.akita-verifierdepends onakita-config,akita-schedules, andakita-params. It receives a validated trusted catalog and never reaches planner search.- Verifier-only integrations should use
akita-verifier+akita-types+akita-config, not the umbrellaakita-pcspackage.
End-to-end lifecycle
- Preset and trusted catalog selection. The caller picks a
CommitmentConfigpreset and loads the matching schedule artifact from the same trusted parameter source used for setup or preprocessing. The caller constructs oneAkitaCommitmentScheme<Cfg>with that catalog. The catalog contains complete expanded rows. Planner search remains offline. Each row selectsSubringCoefficientPackingorEvaluationTracefor every nonterminal fold. EOR is present only for an evaluation trace opening over a proper extension field. See Fold path and field geometry. - Setup.
akita-setupscans the rows in the scheme's trusted catalog and expands the setup (Ajtai matrices and stride envelopes) to cover the requested capacity. - Commit. The application consumes its polynomials into a reusable
CpuBackendand commits the imported source usingGroupContext. The result contains a public commitment and an opaque handle retaining the exact source and commitment parameters. Scheduler mode selects the scalar row when the group has no precommitted groups, or the exact grouped row when it does. Explicit mode validates caller-supplied root parameters. A group committed under a scalar row may later be supplied as a precommitted group. - Claims. The caller supplies ordered
PolynomialGroupClaims; each group owns its complete point, evaluations, and commitment. - Prove.
batched_provereceives retained commitment handles and public claims. The backend checks that each claim matches its commitment before preparing a fresh proof session. The generic prover walks the schedule, absorbs backend messages, samples challenges, and assembles the proof. Source coefficients and witness arithmetic remain inside the backend. - Verify.
batched_verifyresolves the proof row digest in the trusted catalog, replays nonterminal sumchecks and relation-matrix evaluations, then closes the terminal with direct consistency/A and weighted trace checks. The proof never supplies schedule bytes. Prover and verifier sharebind_transcript_instance_descriptorso Fiat-Shamir challenges match.
Entry points: crates/akita-pcs/src/scheme/mod.rs, crates/akita-prover/src/protocol/prove/root.rs, crates/akita-verifier/src/fold/verify.rs.
Further reading: Configuration and planning, Setup offloading, Proving, and Verification.
Recursive setup offloading adds one setup-only Stage 3 message group at each nonterminal producer whose successor consumes a setup prefix. Its wire payload is the setup claim, the setup-prefix evaluation, and one degree-two sumcheck over the native setup domain. Its round count and planned size do not depend on the successor witness length. The setup offloading chapter follows this path from offline planning through the recursive verifier handoff.
Prover consumer boundary
Protocol orchestration passes private state as associated handles through
OpaqueProverConsumer. It owns transcript order, public plans, commitments,
claims, and round messages. The selected consumer owns opening buffers, fold
responses, compression witnesses, recursive witnesses, and mutable sumcheck
and extension-opening sessions.
One CpuBackend implements the opaque contracts directly. Physical routing,
prepared setup storage, and cache policy live in akita-cpu-backend. The
generic prover has no production dependency on that crate. Source import and
persistence are application/backend operations. Setup prefixes enter generic
proving as ordinary reusable commitment handles with checked public metadata.
A shared ConsumerIdentity binds all fold levels to the same setup. A
ProofContext identifies an active proof, fold level, and source group before
private preparation starts. Witness assembly checks those identities before
consuming its inputs, and checks that each accepted fold carries its original
public challenges. EOR openings also bind to the exact witness operation that
produced them. Finishing or abandoning a proof invalidates its retained scope
leases; round operations check those leases without locking the scope registry.
Ring-dimension ownership
The cyclotomic ring dimension is schedule-derived shape metadata, not a
type parameter of the protocol. Protocol data — commitments, hints, proofs,
claims, and root polynomial storage (DensePoly<F>, OneHotPoly<F, I>, and
their enum wrapper) — is flat field-element vectors (RingVec<F>). Per-level
CommitmentRingDims (d_a / d_b / d_d from
CommittedGroupParams::role_dims()) is
the operation authority for how those vectors are interpreted; levels may
differ. Here, role is the historical protocol name for a commitment matrix's
fixed job: A carries the relation witness, B commits the next witness, and D
commits the opening digits. The matrices do not switch roles when their ring
dimensions change. User-facing prose therefore calls a non-uniform tuple such
as 128/64/64 per-matrix ring dimensions and a change between levels a
ring-dimension transition. [validate_schedule_ring_dims] checks every
scheduled dimension directly against the field's dispatch and NTT support.
The public setup is one flat field stream with no ring dimension.
A, B, and D matrix dimensions form a separate admission domain and are all at
least 64. Compressed commitments derive their two smaller dimensions directly
from the modulus profile (q128: 16/8, q64: 32/16, q32: 64/32). Those
compression-only dimensions never become CommitmentRingDims and never reduce
the ordinary relation's common coefficient block.
Every function on the prove/verify path has one of two roles:
- Orchestration reads schedule types, drives the transcript, and moves
D-free storage. It never carries
const D. - Kernels (NTT, digit decomposition, commit/opening folds,
ring-switch arithmetic) are const-generic over
Dand receive extracted numbers, never schedule types.
The bridge is the operation adapter: a D-free function that extracts the
ring dimension of the specific data one operation touches and enters the
kernel through akita_params::dispatch_for_field! exactly once,
returning D-free storage. Dispatch is per operation — never per level or per
proof — so that per-matrix ring dimensions inside one fold (d_a/d_b/d_d,
see specs/runtime-ring-cutover.md) reduce to feeding different
dimensions to different adapters. CommittedGroupParams::role_dims() names
the per-matrix ring dimensions; prove and verify hot paths dispatch on
d_a(), d_b(), or d_d() per operation, not on a single fused dimension.
The normative contract (discriminator rule, forbidden facade/level-
monomorphization patterns) lives in specs/runtime-ring-cutover.md.
Mixed-dimension malformed proof rejection is covered by
crates/akita-verifier/tests/mixed_d_rejections.rs through the verifier API.
Core types
| Type | Role |
|---|---|
AkitaError, akita_error::checked | Shared protocol failures and reusable checked formulas for sizes, offsets, ranges, alignment, and exact division |
AkitaCommitmentScheme<Cfg> | Stateful top-level PCS orchestration that owns one trusted catalog for setup, commitment, proving, and verification (akita-pcs) |
AkitaProverSetup<F> | Prover setup wrapper around a materialized prefix of the dimension-free public field stream |
Commitment<F>, RingVec<F> | protocol commitment and field-vector storage |
CommitmentRingDims, validate_schedule_ring_dims | A/B/D commitment-matrix ring dimensions and schedule validation |
CommitmentConfig | Single user-facing trait for every per-config policy hook (algebra, exact SIS profile, decomposition, layout, schedule, transcript bind, prove/commitment params). Verifier-reachable hooks return Result<_, AkitaError> |
CommittedGroupParams | One fold's ordered groups, shared D matrix, payload mode, source encoding, and witness chunk layout |
FoldParams, TerminalFoldParams, FoldSchedule | Verifier-visible nonterminal, terminal, and complete schedule structure |
PlannerPolicy | Cfg-free projection of a preset for akita_planner::find_schedule; derive via akita_config::policy_of::<Cfg>(chunking) |
DensePoly, OneHotPoly, CommitmentSource, CommitmentExecutor | D-free polynomial storage, commitment representations, and the checked split-or-fused commitment boundary |
ProverBackend, focused opaque kernel traits | Public protocol operations with backend-owned opening, EOR, fold, and sumcheck state |
WitnessLayout, WitnessUnitLayout | Canonical digit-innermost group-and-chunk ranges (opening layout) |
Vec<u8> returned by batched_prove | Canonical Spongefish argument stream, consumed in protocol order by batched_verify with EOF and grinding-plan completion |
PolynomialGroupClaims | One commitment group's complete opening point, evaluations, and commitment |
OpeningClaims | Ordered group-owned public claims in transcript order |
OpeningClaimsLayout | Value-free group arities and polynomial counts for setup and schedule lookup |
GroupCommitPhaseParams, CommittedGroup | Source-free public commitment geometry and its commitment rows |
SourceHandle, CommitmentHandle | Backend-owned immutable source and reusable source-retaining commitment |
ProverOpeningData, SelectedProverOpeningData | Ordered opaque commitment handles bound to public claims and one exact schedule selection |
OpeningScheduleSelection, GroupBatchStatement | Exact generated-row identity and verifier-side self-describing opening statement |
ValidatedScheduleCatalog | Config-free, semantically audited expanded rows with canonical lookup indexes and artifact I/O |
TrustedScheduleCatalog<Cfg> | Config-bound trusted parameter passed to setup, prover, and verifier APIs |
| Spongefish prover/verifier states | Fiat--Shamir state, proof emission/receipt, domain separation, challenges, and EOF checking |
AkitaInstanceDescriptor | Canonical transcript preamble binding algebra, setup, plan, and call shape |
Opening batch kernels validate one authoritative challenge partition against every
source and return one aggregate witness per requested chunk. The protocol combines
their z values into the global fold witness; non-fused backends reuse the public
checked aggregator within each chunk.
Per-fold execution ownership
The batched_prove API keeps one transcript while assigning each
successor fold to a registered backend instance. A typed executor owns its local
session and setup-prefix handles. The coordinator carries a public continuation
(level, commitment binding, challenges, and openings) separately from an opaque,
owner-tagged witness/material pair. Handle pairs and transfer packets are erased
only at dispatch; all arithmetic kernels keep their associated handle types.
Backend routing
Backend routing is always available through batched_prove; it requires no
Cargo feature. A nonterminal fold reduces the current claims to an opening of
a successor witness. The complete successor witness need not be smaller than
its input.
Before preparing any executor, a caller-defined policy resolves the owner of every fold. Each producer commits its successor once. On a switch, the source exports a typed packet, a registered bridge converts it, and the destination imports local handles synchronously. The source finishes its sumchecks before the destination executes its fold. The terminal fold can have its own owner as well.
Construct BackendRegistry<Cfg>, register each backend with its local
akita_prover::SetupPrefixProverRegistry. Registration returns a BackendId.
Pass the registry, typed opening inputs, and route to batched_prove.
FixedFoldRoute::new(vec![a, b, a]) assigns folds 0, 1, and 2 to those registry
entries. Custom FoldExecutionPolicy implementations select every level through
choose_backend, called once per level in order before preparation; its current
owner is absent at level 0. Choices remain fixed throughout the proof. The
registry dispatches the root to the selected executor, checks its commitment
handle family, and validates that the handles belong to that instance. The route
stores only IDs. Each instance supplies the prefix handles needed by its folds
and successor commitments. Registration builds a union of public prefix slots
and rejects conflicting public values for a shared slot ID. Public agreement is
checked once for the immutable registrations; each selected executor must still
have its required local handles. Registration also rejects duplicate instances;
IDs from another registry reject. Route implementations own any cost model;
Akita does not request or compare cost estimates.
Backends implement SuccessorExportKernel and SuccessorImportKernel alongside
ordinary typed kernels. Backend-provided conversions implement SuccessorBridge
on Edge<A, B>. Register the bridge explicitly with
registry.register_bridge::<A, B>()? before selecting a switch. Same-type
instance switches (two CpuBackends) still need
register_bridge::<CpuBackend<F, E>, CpuBackend<F, E>>()?. Heterogeneous routes
register each directed edge (for example PrivateCpu ↔ CpuBackend). For an
application-owned converter, use registry.register_bridge_with::<A, B>(convert)?. It accepts a function or closure from A::ExportPacket and the
handoff plan to B::ImportPacket, allowing applications to connect
dependency-owned backends without implementing a foreign trait. Both
registration APIs share the same type-pair key and reject duplicates. A missing
bridge or foreign ID rejects before any executor is prepared. Only selected
instances are prepared, and their prefix handles and fold capacities are checked
before opening the transcript. Akita never silently reroutes a proof. A single
instance needs no bridge: same-ID choices retain native handles without export,
conversion, or import.
The handoff is blocking: export a typed packet, convert it to the destination's
packet, then validate and import both handles. Every import packet exposes
HandoffMetadata: the identity of this transfer and the logical witness
geometry. The destination checks this metadata against the handoff plan before
adopting private payloads. The coordinator dispatches typed bridges without
prescribing payload encoding. CPU self-edges share immutable packed witness and
material storage. External bridges can construct
CpuImportPacket::new(descriptor, sections) with packed or signed digits,
canonical field coefficients, and compression sections described by
CpuPacketDescriptor. These section types and encodings belong to
akita_cpu_backend; other backend pairs can use their own packet formats. CPU
exports provide into_sections() for conversion to another representation.
Import checks section lengths, the admitted handoff, digit bounds, and canonical
encodings. Portable packets carry logical witness digits only; CPU import
derives the tensor representation when needed. Native CPU self-edges retain the
private transformed cache through shared storage. For outer successors, import
trusts that the bridge's inner rows and compression material reproduce the
public commitment; it checks geometry and canonical encoding, and the verifier
checks consistency. Terminal successors also cross-check the imported inner rows
against the public fields. Switching retains the producer's handles until its
sumchecks complete. The CPU scheme method uses this same prover with every level
assigned to its supplied backend. Routing does not change the setup, commitment,
transcript, or proof format.
Before any proof computation, the coordinator calls prepare_executor on each
selected backend to open its local proof session. It then calls begin_fold for
every assigned level to validate that level and its successor commitment work
before opening the transcript. Preparation does not require a backend to execute
unassigned levels. All prepared sessions use ProofScope to finish on success
or abort on failure, including scopes whose completion fails. A registry
supports repeated proofs, with one active proof at a time.
Implementation: crates/akita-prover/src/protocol/prove/registry.rs,
crates/akita-prover/src/protocol/prove/execution.rs,
crates/akita-prover/src/backend/transfer.rs, and
crates/akita-cpu-backend/src/opaque/transfer.rs. Design record:
specs/dynamic-backend-bridges.md. Regression coverage:
crates/akita-pcs/tests/dynamic_backends.rs.
Configuration and planning
This chapter explains how a preset becomes a concrete recursion schedule. It
covers the CommitmentConfig trait, the fold parameters stored in a schedule,
and the planner that searches for schedules and prices their proof size offline.
CommitmentConfig and presets
The single user-facing trait that defines every per-config policy hook (algebra,
exact SIS profile, decomposition, layout, schedule, transcript bind, prove params), and
the fp32 / fp64 / fp128 preset families built on it.
Both field roles live on the trait: Field carries committed witnesses, setup
matrices, and SIS, while ExtField carries public opening points, claimed
evaluations, and Fiat-Shamir challenges. The protocol geometry gates on
whether the two roles coincide (EXT_DEGREE == 1, all fp128 presets) or
claims live in a proper extension (EXT_DEGREE > 1, fp32 / fp64), never
on field bit-width. See
Fold path and field geometry.
CommitmentConfig selects bounded adaptive A, B, and D domains. It does not
carry a separate default ring dimension.
The resolved schedule owns every dimension used by setup preparation,
commitment, proving, and verification. Setup-prefix slots also record the
dimension selected by the fold that consumes the prefix.
Implementation map
crates/akita-config/src/lib.rs:54-120.crates/akita-config/src/proof_optimized/.crates/akita-planner/README.mdfor the current planner/config boundary.
Runtime witness chunking
A deployment can choose how many witness chunks it uses and how many leading folds remain chunked without defining another configuration type. For example, two chunks across four leading folds use:
#![allow(unused)] fn main() { let chunking = akita_params::ChunkedWitnessCfg { num_chunks: 2, num_activated_levels: 4, }; let policy = akita_config::policy_of::<Config>(chunking); }
The same chunking value is an explicit argument to
TrustedScheduleCatalog::<Config>::from_artifact_bytes or
AkitaCommitmentScheme::<Config>::from_schedule_artifact. Config still fixes
the field types, decomposition, security policy, and challenge rules. Preset
chunking values are conveniences for callers generating the packaged fixtures;
they do not override the runtime argument. These presets live in
akita_params::MultiChunkProfileId (for example, MultiChunkProfileId::W2R3.cfg()),
with packaged inventories selected by family_row! in
akita-planner/src/generated_families.rs.
Packaged fixture paths are keyed by family name and contain one geometry per name. The remaining geometry-named config types identify these fixed fixtures; they are not required to use runtime geometry. Applications can use the same base config for multiple catalogs, assigning each its own path and supplying its expected geometry explicitly.
The fixture helpers empty_emit_spec and emit_spec_for_family take explicit
chunking. Preplans are reused only for matching geometry. Precommitted producer
profiles remain independently selected: a consumer's geometry does not change
an already committed producer.
The planner validates geometry and searches for schedules. Catalog admission checks the expected policy digest and audits every row, including chunking at each fold. A valid chunk count and depth do not guarantee that a particular polynomial shape admits a schedule. The catalog retains the exact policy that passed validation, so grouped planning can reuse it without reconstructing geometry from a preset.
Chunking and the catalog are trusted preprocessing inputs. Proofs select an
admitted row; they cannot change this policy or supply replacement schedules.
One verifier binary and one Config type can use multiple independently owned
catalogs with different chunking. No environment variable or process-global
configuration is consulted by Akita verification.
Bounded committed sources
The fp128::DenseBounded preset is for dense polynomials whose centered
coefficients fit within a declared signed width of 65 bits. This range is
[-2^64, 2^64 - 1], so it contains every u64. The narrower declaration lets
the artifact schedule use the actual source range instead of charging every
coefficient for the full 128-bit field width. Commitment rejects a source that
does not fit the declared interval.
This preset expects the fp128_dense_bounded family artifact. Applications
load and approve those bytes through the same trusted parameter channel as
their other preprocessing data.
External catalog rows serialize one expanded schedule. The root groups determine the committed profiles, which the validated catalog retains for lookup. Resolving a key, profile, or selection borrows the catalog's row.
SetupRequirements::from_catalog computes the matrix capacity and recursive
prefix slots together, and records the capacity bound it was computed at.
SetupRequirements::union combines requirements from several catalogs at the
same bound. Setup construction reuses those requirements when loading,
repairing, or generating a setup. Independently supported precommitted groups still
contribute to matrix capacity when their larger grouped schedule exceeds the
requested bounds.
Schedule and fold parameters
A FoldSchedule stores one root FoldParams, zero or more recursive
FoldParams, and one TerminalFoldParams. Each nonterminal FoldParams points
to one CommittedGroupParams. That value owns the fold's groups, the shared D
matrix, payload mode, ring-relation mode, source encoding, and witness chunk
layout.
The groups are stored in protocol order. An incoming setup prefix comes first,
then ordinary precommitted groups, and the fold's own new group comes last.
Each GroupOpenPhaseParams holds a frozen GroupCommitPhaseParams and the
opening plan chosen by the consuming fold. A setup prefix is the group whose
setup_natural_len is set. There is no second prefix identity or separate
producer choice to keep in sync.
The fold owns one open_matrix for the complete D product. Each group owns its
opening basis and digit depth through GroupOpeningPlan. The verifier checks
this ownership, the group order, matrix dimensions, decomposition depths, and
witness lengths before it uses the schedule.
Implementation map
crates/akita-params/src/layout/params.rsdefinesCommittedGroupParams.crates/akita-params/src/schedule/profiles.rsdefinesGroupCommitPhaseParams.crates/akita-params/src/layout/params/precommitted.rsdefinesGroupOpenPhaseParamsandGroupOpeningPlan.crates/akita-params/src/schedule.rsdefinesFoldParams,TerminalFoldParams, andFoldSchedule.crates/akita-schedules/src/resolve.rsvalidates artifact rows before the prover or verifier uses them.
The planner and proof size
Normal planner search is Cfg-free. The optional catalog-gen feature enables
akita-config, so table-emission binaries can name concrete
CommitmentConfig presets. The emitter writes fully expanded external family
artifacts. Runtime proving and verification resolve rows from the explicitly
supplied TrustedScheduleCatalog<Cfg> and never run planner search. Shared
proof-size formulas remain verifier-reachable and reject malformed input with
an error rather than panicking.
Implementation map
crates/akita-planner/README.mdfor the current planner overview, search model, and artifact generation.crates/akita-planner/src/owns search and emission. Runtime catalog expansion and audit live incrates/akita-schedules/src/.crates/akita-params/src/proof_size.rsandcrates/akita-params/src/layout/proof_size.rs(nonterminal_level_layout, planned witness sizing).crates/akita-planner/src/generated_families.rs,crates/akita-planner/src/emit/, andcrates/akita-schedules/src/artifact.rs.book/src/usage/profiling.mdand.github/workflows/profile-bench.yml.
Multi-chunk fold prefixes
ChunkedWitnessCfg::num_activated_levels counts folds from the root at level
0. The scheduler applies num_chunks to those leading folds and uses one
chunk at every later fold. MultiChunkProfileId provides W2, W4, and W8
profiles for R1, R2, and R3. For example, W4R3 keeps four response chunks at
levels 0, 1, and 2, then switches to one chunk at level 3. The terminal step
closes the remaining witness rather than adding another chunked fold.
The fp128 R3 companions ship separate external artifacts, including W2R3, W4R3, and W8R3 recursive setup companions. Regression tests check the exact three-fold prefix and single-chunk suffix. They also check that changing the third fold's chunk count without recomputing its geometry fails catalog admission.
Recursive setup catalogs
Ordinary configuration catalogs use direct setup evaluation. The supported
RecursiveCommitmentConfig<Cfg> adapters select separate catalogs that may
carry a committed setup prefix into the next fold. Keeping the catalogs
separate prevents an ordinary verifier from accepting a recursive setup shape
under a direct configuration.
The planner prices the Stage 3 proof and the later prefix opening as part of the complete suffix. Artifact rows record every selected prefix edge. Catalog admission checks those edges and never reruns the search. See Setup offloading for the selection rules, setup artifacts, and recursive claim flow.
Ring-relation cutover
Every nonterminal fold selects one RingRelationMode. QuotientLift adds
explicit quotient witness spans and proves exact lifted polynomial identities.
ReducedEvaluation proves the same native-ring equations after evaluation at
the transcript challenge, using signed-wrap residue kernels instead of quotient
witnesses. The choice is independent of raw versus compressed payload and of
the L∞ versus L2 response-security route.
The currently admitted reduced mode is deliberately narrower than its
algebraic definition. The first two folds and every multi-chunk fold require
subring packing and quotient lift. At later single-chunk folds, the planner may choose one monotone
reduced-evaluation suffix, but only for EvaluationTrace openings with direct setup contribution. Extension-field roots
retain packing because their commitments bind canonical coefficients. A reduced
fold cannot consume an incoming setup prefix, defer the A/B/D setup product to Stage
3, or switch back to quotient lifting later. These are product-scope admission
rules, not claims that the excluded combinations are mathematically
impossible. Runtime schedule validation checks them before proving or
transcript replay.
The suffix search prices both realizations using their exact witness layouts, proof sizes, setup requirements, response models, and successor states. An external artifact row records the selected mode at every nonterminal level. The mode is part of the canonical plan descriptor and transcript preamble; it is not a proof-supplied negotiation field and there is no verifier fallback.
Guided grouped schedule adaptation
Applications sometimes select a schedule for one large final polynomial group
before they know the exact small groups that will already be committed when the
final group opens. akita_planner::find_adapted_schedule handles this offline
case, usually without rerunning the exhaustive planner.
The application supplies a validated scalar ResolvedScheduleRow and a
GroupedGenerationRequest containing exact frozen producer descriptors. The
guided search retains the scalar row's structure: recursive depth, dimensions, block
splits, slices, digit bases, opening choices, relation modes, witness chunking,
terminal shape, and setup-prefix topology. It then rebuilds every value that
depends on the combined groups, including D widths and ranks, witness lengths,
relation rows, setup-prefix lengths, response bounds, grinding parameters, and
proof accounting.
This guided search is a conditional search, not a second global optimizer.
When the scalar structure cannot support the grouped request, adaptation falls
back to the exhaustive offline find_schedule for the same key. It therefore
fails only when the request is invalid or no schedule exists in the audited
domain. The fallback costs one full search, and its row need not retain the
scalar row's structure.
Both searches give every group of an interchangeable class (equal commit-phase profile and source contract) the same root opening. Many identical producers, such as the chunks of one large object, therefore cost one opening choice between them, and planning time grows only slowly with their number. Distinct classes multiply the opening choices; beyond 256 combinations the searches skip the affected root opening dimension instead of enumerating them.
An adapted row is not trusted merely because planning succeeded. The
application merges its selected rows, validates them with
ValidatedScheduleCatalog::try_new, binds the result as
TrustedScheduleCatalog<Cfg>, and regenerates setup for that catalog. Runtime
setup restoration, commitment, proving, proof decoding, and verification continue to
resolve immutable catalog rows and never invoke the planner. Adaptation changes
no proof field, transcript event, or .aks schema.
The normative constraints and failure behavior are recorded in Guided schedule adaptation.
Selective L2 candidates
The coefficient L∞ route remains available at every fold. A production
preset may also enable the typed L2 response model. Every shipped
fp32, fp64, and fp128 dense and one-hot family enables it. This includes each
generated multi-chunk and recursive companion.
The planner always retains the universal L infinity candidate. When typed moments are available, it also evaluates the modeled L infinity depth. From level 3 onward, an enabled family evaluates the same canonical block split with an L2 A matrix for response bases 8 and above. The planner keeps an eligible L2 alternative only when it lowers the A rank. Basis 8 uses the same fused norm and range-image leaf as larger bases, with its class-indexed source prepared lazily because it has no product-stage prefix.
The planner estimates the squared norm of the actual recursive witness. It applies the following rules.
- A balanced signed-digit root uses the deterministic maximum squared digit
energy for every coefficient, summed over the digit planes its declared
source bound needs. A bounded source stops short of the field width, so its
final plane is charged only the range the bound leaves rather than a full
log_basis. A one-hot root uses the canonical coefficient table: each policy-owned source chunk contributes at most one coefficient of magnitude one, distinct chunks occupy distinct coefficients, and the peak coefficient square is one. - The Z part uses the centered residues of a rounded normal variable. Its variance comes from the previous source energy and the challenge energy.
- The E and T parts, plus the R quotient part when present, use the centered field digit moment for every live scalar. A reduced-evaluation fold has no R quotient span. The final digit plane uses its actual remaining field width.
- Negative binary compression contributes one half unit of expected energy per coefficient.
- Extension tensor packing multiplies the logical energy by
(2K - 1) / K, whereKis the extension degree.
The planner rounds each source estimate upward while retaining seven leading
bits. This adds less than 1/64 relative error and keeps the suffix search
small. It then multiplies the source estimate by the challenge squared energy,
a 1.03 model envelope, and a 40/39 response allowance. If the model envelope
bounds the conditional mean, Markov's inequality gives at least 1/40
acceptance probability on each independent attempt. The protocol permits 4096
attempts, so the resulting exhaustion bound for one response is below
2^-149.
The 1.03 factor covers approximations in the normal, field digit, challenge covariance, and finite mixing models. It is an empirical completeness margin, not a soundness claim. Response-model diagnostics measure exact source and response energy in complete production proofs. The benchmark parser joins each measurement to the planned fold in the same run, rejects a successful run whose response exceeds its frozen cap, and records cap utilization and nonce attempts for every L2 fold. Historical measurements are evidence, not compiled unit test constants.
The field digit model is exact for uniform power of two residues, apart from the negligible pseudo-Mersenne boundary. Recursive setup values can retain correlation. This usually lowers their E, T, and R energy, so the model is conservative. Separate component validation found at most 2.24 percent unfavorable error.
The suffix comparison includes the norm proof, A payload, next witness, later
folds, and terminal response. A smaller A rank can reduce the next witness
enough to remove a fold, but the planner keeps L∞ when the extra norm proof
costs more than the suffix saves.
This model affects completeness and schedule selection only. Once the planner selects a route, its concrete cap is frozen into the artifact schedule. The prover rejection samples against that cap and the verifier enforces the same value. The SIS calculation therefore still uses the public accepted cap and does not trust the statistical model.
If the typed model is disabled, the geometry is ineligible, no Euclidean SIS row exists, or the L2 route does not lower the A rank, the planner keeps the L infinity candidate. Runtime expansion never reruns the model. It only checks the frozen schedule.
Subring coefficient packing candidates
Within the two-level adaptive dimension prefix, coefficient-packing candidates
search the A ring dimension and the challenge subring dimension together. For
each pair the planner derives the packing factor from d_A = k h s. It rejects unsupported challenge families and
invalid D divisibility before it constructs matrices.
The planner does not minimize s, h, or d_A directly. It keeps the same
complete-schedule objective as other candidates. Depending on the catalog
policy, the numeric prefix is either proof payload then total setup, or first
direct-setup capacity then proof payload then total setup. Exact numeric ties
prefer the smaller root output witness before the canonical descriptor breaks
the final tie. This allows a larger A ring to win when its lower module rank
reduces the complete setup or proof suffix.
The first two committed folds require coefficient packing and quotient lift, regardless of chunking. Every later multi-chunk fold has the same requirement. A three-level multi-chunk profile therefore uses packing at levels 0, 1, and 2, with the configured suffix ring dimensions at level 2. A mandatory packing state with no complete packing assignment is unsupported. Single-chunk nonterminal folds at level 2 or later may choose coefficient packing or evaluation trace where their source encoding supports it. The terminal uses evaluation trace. Its seed is priced separately, so a zero EOR packing candidate cannot be mistaken for a terminal opening.
A clear terminal L2 candidate has no recursive norm proof. The verifier checks the decoded response norm directly. The planner may use the certified energy to estimate a smaller Golomb payload for candidate comparison. The scheduled Golomb byte cap and the payload grind remain unchanged.
External schedule identity includes the cap policy and the separate L2 table digest. Artifact decoding audits the route, cap, proof shape, and A rank against that identity. A mismatch between the preset policy and supplied catalog is an error.
Source type is not part of runtime schedule identity. Dense and one-hot
presets own different offline policies and external catalogs, but equivalent
polynomial groups have the same runtime geometry. In particular, one-hot chunk
size is an input to UnitOneHotFoldPolicy; it is not serialized in a
commitment, proof, opening layout, or transcript.
Setup and commitment
Akita commits to a polynomial by arranging its table entries into ring elements, decomposing those elements into small digits, and applying public matrices. The result binds the table that the prover will later open. This chapter follows one polynomial through that computation before describing matrix reuse and the dense and one-hot implementations.
Setup
The public setup starts from a seed. Akita deterministically expands the seed into a vector of base-field elements, then interprets checked ranges of this vector as matrices of ring elements. There is no secret trapdoor to retain or discard. Both parties must use the same seed and matrix geometry.
The instance descriptor binds the setup seed identity and selected schedule before protocol replay. Expanded matrix files and prepared NTT views are caches derived from that public identity. Loading a cached coefficient matrix checks that it matches the seed.
Exact public-stream derivation
AkitaSetupSeed contains two values: a 32-byte public seed and a versioned
derivation method. The current method is Shake256PagedV1. Versioning the
method prevents a change to page size, domain separation, or field sampling
from silently changing the setup identified by an existing seed.
The derivation splits the infinite field stream into pages of 4096 elements. For page index , it initializes one SHAKE256 stream with the following length-prefixed fields, in order:
| Label | Value |
|---|---|
domain | akita/commitment/public-field-stream |
derivation | shake256-paged-v1 |
page_field_elements | 4096 as little-endian u64 |
seed | the 32-byte public seed |
field | the protocol-field modulus as 32 big-endian bytes |
page | as little-endian u64 |
A length-prefixed field is encoded as the little-endian u64 length of its
label, the label, the little-endian u64 length of its value, and the value.
The explicit field modulus prevents equal seed bytes from identifying the same
coefficient stream in two different fields.
The page then calls Field::random repeatedly on that SHAKE256 reader. The
production fields use exact rejection sampling, so this is a uniform field
stream rather than a fixed-width integer stream reduced modulo the field
modulus. Pages
may be generated in parallel; concatenating them by page index gives the same
prefix as sequential generation.
One stream, several matrix views
Ring dimensions do not enter the derivation. Requests for the same number of field elements return the same prefix whenever the setup seed and field agree. The schedule determines how to read that prefix as a matrix.
A matrix view with r rows and c columns contains r × c ring elements.
Each ring element holds D field coefficients, so the view reads
r × c × D coefficients from the start of the stream. It groups every D
coefficients into one ring element, then fills the matrix one row at a time.
The matrices , , and each read from field index zero. Their prefixes overlap. The setup therefore needs enough storage for the largest matrix view required by the schedule, not the sum of all views.
This prefix sharing does not require the three roles to use the same ring dimension. For example, two views that each use 4096 field coefficients read the same random prefix even if one groups it into 64-coefficient rings and the other into 128-coefficient rings.
The witness column order is defined by the relation layout, not by setup generation. Akita keeps digits consecutive within each logical value. Exact A, B, and D column orders, including coefficient packing and sliced B layouts, are documented in Advanced relation layouts and Opening points and digit-innermost layout.
A recursive setup schedule may require commitments to selected power of two prefixes of this vector. Setup construction materializes exactly those prefix slots and checks that no required slot is missing. The prover later opens a slot when a fold defers its setup contribution. See Setup offloading for the complete lifecycle.
From a table to inner commitments
Begin with one polynomial, one chunk, and a common ring , where is the base field and is the ring dimension. An element of stores field coefficients. Ring multiplication wraps powers with the rule .
The polynomial's table supplies coefficients . Here selects a ring coefficient, a position within a block, and a block. Pack one ring element per position:
This is a representation of the table. It does not evaluate the application polynomial at . Field to ring reduction explains how an evaluation of the table becomes a claim about these rings.
The inner commitment needs short inputs. Let be the public recomposition weight for inner digit . Decompose each position coefficientwise into digit rings :
The configured digit range bounds integer representatives of the coefficients. Small digits keep the subsequent commitment and folding relations within their certified norm bounds.
Collect the digits of block into , in position order with digit index innermost. For positions and digits per position, the public inner matrix has shape . Its image is
For a small algebra example, take , one A row , and a digit block . Equation (3) gives . A second block gives using the same A row. These tiny parameters only illustrate the computation; production schedules choose security-sized matrices.
Every block now has a short vector of A outputs, but the number of such outputs still grows with the number of blocks. The outer matrix compresses that collection.
The outer commitment and public payload
Let index an A output row. Decompose each using outer weights , then concatenate the resulting digits in the outer matrix's column order:
The hat distinguishes the short digit representation from the recomposed inner images . The two matrix applications in (3) and (4) form the two-tier Ajtai commitment.
A standalone commitment transmits a compressed payload for . Two rank-one maps form the compression chain. Each map decomposes its input coefficients into digits in , packs those digits into its native ring, and applies its public matrix. The digit weights are positive powers of two, interpreted in the base field. The first map produces 256 bytes and the second produces the 128-byte payload . The complete source image must fit within 8 KiB.
The ring dimensions are profile-owned:
| Modulus profile | First map | Second map |
|---|---|---|
| q128 | 16 | 8 |
| q64 | 32 | 16 |
| q32 | 64 | 32 |
These smaller rings belong to compression. A, B, and D retain their own dimensions, each at least 64. Repacking coefficients between these rings is a specified coefficient map, so it must not be treated as an arbitrary ring homomorphism. The physical fold relations explain how the proof checks recomposition and every compression map.
Later recursive commitments can use a schedule-selected raw payload instead. Standalone commitments and setup-prefix precommitments remain compressed. Recursion describes where the raw suffix is admitted.
What the prover retains
The default portable state is a PortableCommitmentHandle owned by the CPU
backend. Protocol code can inspect its shape but cannot borrow its inner rows,
compression witnesses, or quotients, or serialize the handle directly.
Setup-prefix persistence uses the backend-owned SetupPrefixProverRegistry
codec; the verifier registry contains only public commitments.
Commitment produces a public committed group and a prover-only hint. The group associates its payload with the frozen commitment profile. That profile fixes the geometry needed to interpret the commitment, including the inner and outer decompositions and B slicing.
The hint retains the semantic inner images for each polynomial. For compressed commitments it also retains the packed compression digits and, when quotient lifting is used, the compression quotient images. It does not store a second copy of the public commitment or the complete outer digit table . The CPU backend reconstructs those digits from the retained inner images.
The hint avoids repeating work during opening. It is not evidence that the verifier trusts, and it does not replace access to the committed polynomial. The verifier receives the public commitment and opening proof, then checks the corresponding relations.
Where the opening matrix enters
D depends on the opening geometry and is used when proving an evaluation. For the evaluation-trace opening method, the prover computes a ring partial for each block, decomposes these partials into , and forms
The opening proof carries the compressed payload , or the raw in an admitted raw fold. Equation (5) binds the opening digits. A separate scalar relation recovers the requested evaluation from them, as derived in the Akita fold.
This is why a standalone commitment profile freezes A and B without requiring D. The query is not needed to commit. Once the query is known, the opening schedule selects D and the proof connects its opening digits to the same source used by A and B.
Dyadic B slicing
At absolute commitment levels zero and one, a compressed commitment may reuse
one smaller physical B matrix across S consecutive block ranges, where S
is 1, 2, 4, or 8. D is never sliced. Raw commitments and deeper levels require
S = 1. Setup prefixes are separate frozen precommitments and may use slicing
at any consumer level.
The block ranges are the proportional dyadic ranges
[floor(i * F / S), floor((i + 1) * F / S))
for F live blocks. Sliced commitments require S <= F, so every B slice is
nonempty. Each slice is assembled in the ordinary B column order. Within each
polynomial-major segment, a shorter slice receives its own zero suffix before
the next polynomial segment begins. The prover then applies the same physical
B matrix to every slice.
The resulting B images remain logically separate. If B has n_B rows, the
relation has S * n_B B rows in slice-major order. Akita stacks the complete
image and runs one canonical two-map F compression chain over it. The full
stack, not one physical image, must fit the unchanged 8 KiB compression-source
limit.
This separates physical and logical cost:
- SIS rank and setup storage use the smaller physical B width.
- Relation rows, compression work, and proof sizing use the complete logical stack.
- Direct and recursive setup contribution evaluation combine all logical slice weights before scanning the physical B matrix, so each physical entry is evaluated once.
The planner checks every admitted slice count. Proof-focused selection keeps the counts through complete schedule scoring. Setup-focused selection keeps the smallest count at the exact local setup floor. The selected count belongs to the commitment group and is frozen in standalone profiles, setup-prefix metadata, descriptors, and trusted external catalog identity.
Relevant implementation sources:
crates/akita-params/src/commitment_slicing.rscrates/akita-cpu-backend/src/commitment/api.rscrates/akita-types/src/setup_contribution/plan/physical_b.rs
Public-stream and view sources:
crates/akita-types/src/proof/setup.rscrates/akita-params/src/layout/flat_matrix.rscrates/akita-params/src/dispatch/mod.rs
Dense and one-hot backends
The dense backend decomposes the source coefficients and evaluates the inner
matrix product with CRT and NTT arithmetic. The one-hot backend uses the
source's sparse structure to visit only its nonzero monomial positions. A
one-hot source has at most one nonzero entry, equal to one, in each consecutive
chunk of onehot_k entries. An all-zero chunk is allowed.
Both backends use the same checked commitment geometry and sliced B executor. They differ only in how they produce the inner A image. Prepared setup and NTT caches remain keyed by the physical matrix, so increasing the logical slice count does not create extra stored B matrices.
Code map
crates/akita-setup/src/lib.rsconstructs setup and validates cached public matrices against their seed. Its tests cover seed and cache mismatches.crates/akita-cpu-backend/src/commitment/api.rschecks standalone commitment profiles, computes inner images, and executes sliced outer commitments.crates/akita-cpu-backend/src/commitment/portable.rsdefines the retained prover state and tests its canonical serialization and shape checks.crates/akita-cpu-backend/src/opaque/recursive/commit.rscommits recursive witnesses, selects raw or compressed output, and prepares the A-only terminal handoff.
The production layout can use different native ring dimensions and several polynomials per group. Equations (1) through (5) give the common-ring, single-polynomial meaning; the checked layout determines the coefficient conversions and concatenation in those larger cases.
Transcript and instance binding
Akita replaces interactive verifier randomness with Fiat-Shamir challenges. Prover and verifier derive each challenge from the same public parameters and the same preceding messages. The transcript records that order.
For example, suppose two claimed values will be checked through . Both values must be fixed before the transcript produces . If a prover could choose afterward, it could cancel a chosen error in . This is why a transcript contract specifies both which bytes are absorbed and when each challenge is drawn.
The transcript layer
Production uses Spongefish's prover and verifier states. Its domain separator includes a backend-specific protocol tag, the caller's length-framed session bytes, and canonical instance bytes. The selected backend is BLAKE2b or Keccak; each has its own protocol tag.
Akita pins Spongefish v0.7.4. Its digest bridge encodes squeeze counters as
fixed-width u64 values, so Blake2b transcript bytes do not depend on whether
the implementation uses 32-bit or 64-bit pointers. Akita keeps a known-answer
vector for this boundary.
Every logical message or challenge has a fixed public diagnostic context record. Proof values use prover emission and verifier receipt, derived or public values use public messages, and verifier challenges use verifier messages. Field atoms are canonical. The one variable-size terminal payload carries a checked length atom before its body.
Production absorbs and squeezes are positional. Context records and callsite labels are diagnostics and do not enter sponge bytes. The backend-specific protocol identifier, length-framed session, canonical instance descriptor, messages, and replay order do enter the cryptographic state. Renaming a diagnostic label therefore differs from changing any of those bound values.
Prover and verifier must execute the same sequence, including challenge lengths and canonical ordering within a batch. Equal proof objects alone do not establish that agreement.
Sparse fold challenges
A fold needs one sparse ring challenge for every (claim, live block) pair.
Akita draws them in claim-major order. It performs only one live transcript
squeeze per commitment group, while still giving each pair an independently
forkable random-oracle coordinate.
The group root
Before the squeeze, the transcript absorbs the complete public draw context:
- group index, number of live blocks, and number of claims;
- total number of challenge coordinates;
- challenge ring dimension;
- counts of coefficients at magnitude 1 and magnitude 2;
- the shared fold-response grinding nonce;
- the coefficient-packing method domain and challenge-subring dimension, when coefficient packing is selected; and
- the operator-norm rejection policy, when the selected L2 route requires it.
The transcript then squeezes one 32-byte group root. Evaluation trace preserves its established domain encoding. Coefficient packing adds a distinct method domain so the same transcript state cannot reinterpret a draw under the two opening methods.
One indexed stream per coordinate
For coordinate index , the sampler initializes a fresh SHAKE256 reader from
group_root || little_endian_u64(i).
Coordinate is claim * num_live_blocks + block. Expanding one coordinate
does not mutate either the live transcript or another coordinate's reader.
This gives the extraction argument the required fork: one challenge can change
while every other challenge and the surrounding transcript remain fixed.
Expanding the whole challenge vector from one shared cursor would give a different oracle dependency. Each accepted nonce has one canonical unsigned LEB128 representation: those exact proof bytes are absorbed into the live transcript before the challenge context is derived. There is no second compact nonce representation or separate nonce absorption.
The indexed readers are an expansion of one transcript root, not additional Fiat--Shamir squeezes and not additional proof data.
Positions, magnitudes, and signs
Suppose the challenge ring has dimension . A configured challenge has
count_pm1 coefficients at magnitude 1 and count_pm2 coefficients at
magnitude 2. The sampler first chooses their distinct positions by a partial
Fisher--Yates shuffle of 0..D.
When the challenge is very sparse, the implementation stores only the swaps touched by that partial shuffle, using scratch for Hamming weight . Denser cases use a fixed stack permutation for better locality. These are two implementations of the same ordered partial shuffle and consume the same random stream.
Every bounded integer draw uses bitmask rejection rather than % D, so the
position law has no modulo bias. After positions are fixed, fresh low bits
choose independent signs. The first count_pm1 positions receive ;
the remainder receive .
Optional operator-norm rejection
An L2 fold may require a challenge whose negacyclic convolution operator norm is below a scheduled threshold. For supported D64 and D128 challenge families, the sampler tests each indexed candidate against the certified predicate and continues reading the same coordinate stream until one is accepted. The search is capped at 4096 candidates.
This rejection rule is part of the public challenge method. The policy and threshold are bound before the group root is squeezed, and the verifier repeats the same deterministic search. Coefficient-packing folds use the L-infinity security route and reject an operator-norm policy.
Implementation:
crates/akita-challenges/src/fold_draw.rsbinds the group context and owns the single transcript squeeze.crates/akita-challenges/src/sampler/xof.rsdefines the indexed SHAKE256 stream and unbiased bounded draws.crates/akita-challenges/src/sampler/position_sample.rsimplements the partial Fisher--Yates paths.crates/akita-challenges/src/sampler/signed_sparse.rsassigns magnitudes and signs.crates/akita-challenges/src/sampler/op_norm.rschecks the certified operator-norm predicate.
AkitaInstanceDescriptor
Before replay, both parties construct an AkitaInstanceDescriptor from the
validated public configuration. The shared
bind_transcript_instance_descriptor helper binds its canonical bytes
through spongefish's DomainSeparator.instance(...).
The descriptor records the following identities:
| Section | What it fixes |
|---|---|
| Algebra | Base modulus and field extension degrees |
| Setup | Decomposition, SIS modulus profile, compression policy, setup seed digest, protocol feature flags |
| Plan | Schedule selection and the effective schedule digest |
| Grinding | The ordered grinding plan and its wire contract |
| Call | Commitment-group counts, polynomial counts, variable counts, opening-layout digest, and basis |
The effective schedule includes the level geometry, payload modes, and each
nonterminal RingRelationMode. Switching between quotient lifting and
reduced evaluation changes the preamble before the ring-switch challenge
. The verifier uses the selected mode and rejects a mismatch.
The descriptor fixes the interpretation of the call. Actual commitment payloads, opening-point coordinates, and claimed values are absorbed during the protocol. Binding only the call's shape would not bind those values.
For example, two calls with identical shapes but different opening values have the same shape metadata. Their transcripts diverge when the claimed values are absorbed. Two calls that interpret identical payload bytes under different schedules diverge at the descriptor.
Root and fold replay
At the root, the descriptor fixes the batch shape. Replay binds group commitments in canonical group order, each group's complete opening point, and the per-polynomial claimed values as public messages. The verifier checks commitment geometry before binding the payloads.
A nonterminal fold then follows these dependencies:
- Prepare the opening claim. If evaluation trace over a proper extension requires extension-opening reduction, replay that reduction first.
- Absorb the complete opening payload, either compressed or raw , then draw the application claim-batching coefficients.
- Consume the fold-response nonce and draw the sparse fold challenges for each group.
- Absorb the next-witness binding. It is a recursive commitment payload or, on the last edge, the terminal inner-image state.
- Draw the ring-switch challenge , followed by the range and row points .
- Replay Stage 1 and Stage 2. Absorb each sumcheck round message before drawing its round challenge. Carry the resulting witness-opening claim to the successor.
- If the schedule offloads setup, replay Stage 3 and carry its separate setup-prefix opening alongside the witness opening.
This order makes the next witness binding independent of the random points that check its relations. The witness itself can remain prover-only until the terminal. Recursion explains what each binding commits to, and the sumcheck stages derive the carried claims.
A recursive successor uses the commitment and opening claim supplied by the previous fold. If a setup prefix is present, its group precedes the witness group. Neither party may reorder groups based on their payload contents.
Extension-opening reduction and terminal replay
Extension-opening reduction has an earlier batching step of its own. The prover first binds the incoming claimed values and reduction partials. The transcript then produces the tensor-mixing challenge and the early coefficients that batch the reduction claims. Every reduction sumcheck message precedes its round challenge.
The reduction's final claims are absorbed before the fold's complete opening payload. Only after that payload is bound does the application batching in step 2 occur. These two batching steps have different inputs and different challenge positions; they cannot reuse a challenge merely because both form linear combinations. The reduction chapter gives the full sequence.
At the terminal, the verifier checks that the response's inner images match the predecessor's binding. After any required extension-opening reduction, it absorbs the ring opening partials, consumes the fold-response nonce, and draws the sparse challenges. It then absorbs the remaining response and performs the direct checks. There is no outgoing commitment or replay of Stages 1 through 3.
Grinding plan and inline nonces
Each proof has one public GrindingPlan, derived from the selected
schedule, normalized opening layout, field tower, and policy. The plan fixes
the order and bit width of every proof-of-work query and bounded
fold-response search. Its digest is part of the descriptor.
Nonzero proof-of-work sites and every fold-response site carry an inline canonical unsigned LEB128 nonce at the exact protocol position where it is used. A decoder does not obtain a nonce count or policy from proof bytes. The plan cursor checks sites in order and must be exhausted when EOF is checked.
The planner accepts only complete schedules whose expanded grinding query
count is less than u32::MAX. If the objective-best candidate exceeds that
capacity, planning treats it as an infeasible path and continues among schedules
admitted by the planner's existing bounded candidate-generation policies.
UnsupportedSchedule means that no feasible schedule was found within this
domain; it does not prove that no mathematically valid schedule exists among
layouts discarded by those policies.
Proof-of-work and fold-response nonces use distinct message kinds and serve different purposes.
Protected challenge queries
Each field challenge site has a loss . The security argument allows at most of the possible challenge values to be bad for the verifier, so one attempt at the challenge lands on a bad value with probability at most . The next subsection shows where a loss comes from for one family of sites.
Grinding makes each attempt cost hash queries on average. The plan chooses the least nonnegative integer with , which keeps the chance per query at most . The calculation uses integers and the actual prime power, including the deficit below a power of two.
At a protected query with grinding target , the prover searches a nonce whose accepted value must fit bits. Each attempt absorbs the canonical nonce, then produces a separate 32-byte predicate. Diagnostic metadata records the grinding site without changing the sponge. The predicate passes when its first low-order bits are zero.
The verifier repeats that predicate check. Only after it passes does replay draw the protocol challenge from the advanced transcript. The predicate is not reused as the challenge. A zero-bit target consumes no proof bits and leaves the transcript unchanged at that site.
The additional seven nonce bits provide room for honest search beyond the
expected attempts. Storage is self-delimiting and canonical; the semantic
width is still checked from the public plan. Schedule selection adds the
per-message maxima, ceil(semantic_nonce_width / 7). This deterministic
cost is not the realized LEB128 wire size. The verifier safety bound is derived
separately from the complete grammar.
The loss of a claim-batching challenge
The problem. A fold often opens several polynomials at once. The prover states claimed values , one per polynomial, and the verifier checks them together instead of one at a time. It draws coefficients from , one fresh value per claim, and the rest of the fold proves the single combined claim . The question is how many bad values this draw has, that is, what loss to price it at.
The tempting answer, . Write for the true value of the th polynomial and for the error in its claim. The combined claim is correct exactly when . If some is nonzero and the errors are fixed before the coefficients are drawn, this is one nonzero linear equation in the , and a random draw satisfies it with probability at most . That suggests .
Why the security argument cannot use it. Knowledge soundness is proved with an extractor: a procedure that reruns a prover that makes the verifier accept and recovers the committed polynomials from its answers. The true values are evaluations of those recovered polynomials, and the extractor only obtains them from the part of the proof that comes after this challenge. Commitment binding does not help. It says an efficient prover cannot produce two different openings of one commitment; it does not hand the argument a single opening, and hence fixed errors , before the coefficients are drawn. So the argument must work from accepting runs alone.
What the extractor does. It reruns the prover from this challenge with coefficient vectors: a base vector , and for each a vector that differs from only in coordinate . The claims were sent before the challenge, so they are the same in every run. Every run also opens the same committed polynomials, or the extractor has found a commitment collision, so every run has the same errors . The base run gives , and run gives the same sum with replaced by . Subtracting the two leaves , so .
For example, with the extractor uses three runs, with coefficient vectors , and where and . The first two runs give , and the first and third give . Both claims are therefore correct.
The resulting loss. The extractor fails only if, for some coordinate , the prover succeeds with one value of and with no other value, the other coordinates held fixed. That costs at most one bad value per coordinate, in all, so the site has loss . Other sites in Akita batch claims with powers of one scalar. That check is a nonzero polynomial of degree at most in , so those sites have loss .
In the production field, is slightly below . One polynomial draws no coefficients and has no site. Nine polynomials give , and lies between 8 and 16, so the site needs , where would give .
Two sites have this form: the evaluation batch of each fold, and the batch
of reduction claims in extension-opening reduction.
independent_batch_loss_factor in akita-types prices both. The
grinding nonce specification
records the contract.
Fold-response search
A fold-response entry carries a canonical unsigned LEB128 nonce whose value must fit the 12-bit search domain, shared by all commitment groups in that fold. The prover previews candidates until the resulting response satisfies the scheduled representation and norm bounds. It commits the winning nonce to replay, or returns an error if the bounded search is exhausted.
The verifier reconstructs the challenges for that nonce and enforces the response bounds. This is separate from the proof-of-work predicate. The PCS binding chapter explains why adversarial nonce trials must be included in random-oracle query accounting.
Integration and regression checks
AKITA_INSTANCE_DESCRIPTOR_VERSION is currently 5. Validation rejects
other versions. Pin an exact Akita revision and rerun prove and verify
integration tests when upgrading; the repository does not promise
compatibility across revisions.
Binding an instance initializes the transcript state for that instance. Application code should use the intended session label and let the scheme's shared binding path construct the descriptor before replay. Prepending application messages to a transcript that will then be rebound does not preserve those messages in the new state.
The current descriptor's SetupSection.protocol_features.zk is
false. Transcript binding does not add hiding or zero knowledge.
The protocol uses a descriptor-bound positional grammar. Context records
capture semantic sites and widths for logging diagnostics without adding
production hashing work. Tests cover prover/verifier vectors, tampering,
truncation, statement/session binding, and EOF; they do not freeze one
proof-byte digest for all future schedules. The grinding grammar and
nonce encoding are documented in
specs/transcript-grinding.md and
specs/grinding-nonce-encoding.md.
Code map
crates/akita-config/src/transcript_binding.rsconstructs and binds the shared descriptor and grinding plan.crates/akita-types/src/instance_descriptor/mod.rsowns descriptor fields, canonical serialization, and version validation.crates/akita-transcript/src/proof_stream.rsowns state construction, context framing, canonical atom codecs, bounded bytes, and EOF-compatible proof transport.crates/akita-params/src/transcript_grinding/plan.rsdefines the ordered plan;crates/akita-types/src/transcript_grinding/replay.rscouples nonce transport, predicate checks, challenges, and plan progress.crates/akita-challenges/src/sampler/xof.rsderives the indexed sparse challenge streams.crates/akita-verifier/src/fold/mod.rsandcrates/akita-verifier/src/fold/terminal.rsenforce fold and terminal replay order.crates/akita-pcs/tests/transcript_hardening.rstests ordering and prover/verifier agreement;crates/akita-pcs/tests/fold_linf.rscovers fold-response nonce behavior and proof roundtrips.
The detailed grinding contract is recorded in the transcript grinding specification.
The proving protocol
One Akita fold reduces committed opening claims and the fold relation to an opening claim about a new recursive digit witness. It proves that the new witness comes from the old committed data, satisfies the fold relation, uses bounded digits, and is ready to be opened by the next level.
This compresses the claim carried forward; it does not guarantee that the full next-level witness is smaller than the input witness. The folded response is only one part of that witness. Opening and inner-commitment digits, auxiliary digits, and the scheduled physical representation also contribute to its size. In particular, a root fold may be non-contractive: its outgoing witness may be as large as or larger than the application source.
The root and recursive nonterminal levels use the same fold engine. They differ in the source they consume and the schedule parameters assigned to them. The terminal level is different: it checks the final clear witness directly and does not create another recursive witness.
This chapter is the map for the proving section. Its child chapters derive the relations, physical layouts, opening methods, and sum-checks in detail.
Inputs and output of one fold
A nonterminal fold starts with four kinds of information.
| Input | What it means |
|---|---|
| Public opening claims | Ordered commitments, opening points, and claimed polynomial values |
| Private source data | Polynomial or recursive witness values plus the hints created when they were committed |
| Public setup | The A, B, and D matrix entries required by this scheduled level |
| Scheduled parameters | Ring dimensions, block geometry, digit bases, opening method, norm route, and proof shape |
The fold streams:
- one schedule-shaped sequence of commitment payloads and sum-check messages;
- one recursive digit witness for the successor;
- one opening claim that binds that witness at the final Stage 2 challenge; and
- when setup offloading is selected, a separate opening claim for one prepared setup prefix.
The witness claim and setup-prefix claim remain distinct. A successor may open both in one grouped fold, but they keep separate commitments, points, values, and source meanings.
One nonterminal fold in order
The prover follows this sequence.
1. Validate the scheduled geometry
The level reads its group parameters from the resolved schedule. It checks matrix roles, ring dimensions, block counts, digit depths, opening methods, payload modes, and any incoming setup prefix before building large tables.
The proof does not get to override these values. They determine the expected message widths and transcript structure on both prover and verifier paths.
2. Prepare each opening
Each commitment group has one complete opening point shared by the polynomial claims in that group. The scheduled opening method determines how the prover turns those claims into fold inputs.
- Subring coefficient packing contracts selected coefficient coordinates and opens the extension-valued claim directly in a smaller challenge ring.
- Evaluation trace expresses the claim through a field-valued trace. When the opening point lives in a proper extension field, extension-opening reduction first converts it to the base-field relation consumed by the fold.
The method belongs to the level schedule. A proof carries extension-opening data only when evaluation trace and a proper extension field require it.
See Fold path and field geometry, Field-to-ring evaluation reduction, and Extension-opening reduction.
3. Fold the source into a response
Transcript challenges combine the source blocks into a shorter response . The opening point also produces partial evaluations that will bind the claimed value to those same blocks.
The response, opening values, and inner commitment values are decomposed into small signed digits. Akita stores those digits in one canonical digit-innermost witness layout. Every later range check, matrix evaluation, recursive handoff, and verifier calculation uses that layout.
See Opening points and digit-innermost layout.
4. Build the semantic fold relations
The core fold statement has four ring-valued relation families:
- the folded response agrees with the source blocks and fold challenges;
- the inner A matrix agrees with the source digits;
- the outer B matrix agrees with the public commitment; and
- the opening D matrix agrees with the opening digits.
The field-valued opening claim is kept conceptually separate, then fused into Stage 2 beside these ring rows.
The basic derivation is in Semantic relations in an Akita fold. Advanced relation layouts extends the same four families to multiple groups, chunks, and role-specific ring dimensions.
5. Choose the physical realization
The semantic B and D commitment values can appear directly as raw payloads, or they can remain hidden behind smaller compressed payloads. Compressed mode adds the two-map commitment chains, their digit witnesses, and their physical rows. It does not change what the four semantic relations mean.
The schedule also selects how to check these ring equations: quotient lifting adds private quotient digits, while reduced evaluation includes ring reduction in public coefficient weights. Each row uses its native ring dimension. Checking ring relations over a field derives both methods and their common handoff to Stage 2.
See Raw and compressed realizations of an Akita fold.
6. Form and commit the successor witness
The relation witness contains the response digits, opening digits, inner
commitment digits, and any compression witness required by the payload mode.
It also contains quotient digits when the relation mode is QuotientLift.
Ring switching lays these values out as the next
field-valued witness. The prover commits to that witness with the parameters of
the successor level.
At the root, subring coefficient packing also controls how sparse challenge coefficients enter the A ring and how shortened partial evaluations enter the relation. See Root fold and ring switching.
7. Run the sum-check cascade
Every nonterminal fold runs two required stages and one optional stage.
| Stage | What it proves | What it leaves behind |
|---|---|---|
| Stage 1 | Every new witness entry is in the scheduled balanced digit range; an L2 route also proves the physical response norm | One range-image evaluation used by Stage 2 |
| Stage 2 | The ring-switched physical relation, Stage 1 output, and incoming opening claim all agree with the committed successor witness | The successor witness opening claim |
| Stage 3 | The claimed A, B, and D setup contribution is the correct product sum for a prepared setup prefix | A separate setup-prefix opening claim |
Stage 3 appears only on a scheduled offloaded edge. In direct mode, the verifier evaluates the setup contribution itself and no Stage 3 proof is present.
See Sum-check stages and Setup offloading.
8. Hand the claims to the successor
The Stage 2 challenge and expected witness evaluation become the statement for the next fold. If Stage 3 ran, its setup-prefix point and evaluation enter as a second commitment group. The transcript binds this exact handoff before the successor samples dependent challenges.
The process repeats until the schedule reaches its terminal level.
Root, recursive, and terminal responsibilities
| Level | Source | Main responsibility | Output |
|---|---|---|---|
| Root | Application polynomial groups | Batch the requested openings and enter the recursive fold path | First recursive witness claim, plus an optional setup claim |
| Recursive nonterminal | Witness and optional setup group from the predecessor | Authenticate the handoff and reduce it to the next opening claim | Next witness claim, plus an optional setup claim |
| Terminal | Final clear witness bound by its predecessor | Check consistency, A relation, evaluation trace, encoding, and scheduled norm directly | Accept or reject |
The terminal has no outer B commitment, no opening D commitment, and no sum-check cascade. Its predecessor already binds the terminal witness through the opening claim that enters the final check.
Recursion and proof shape explains how these records are encoded and connected.
Reading the child chapters
The most useful order depends on what you need.
First protocol reading
- Field-to-ring evaluation reduction
- Semantic relations in an Akita fold
- Raw and compressed realizations
- Checking ring relations over a field
- Opening points and digit-innermost layout
- Fold path and field geometry
- Sum-check stages
Read Root fold and ring switching when you want the complete coefficient-packing derivation. Read Extension-opening reduction for the evaluation-trace path over a proper extension field.
Multi-group or distributed implementation
Advanced relation layouts adds commitment groups, chunks, and different role dimensions to the basic fold. The distributed prover then shows which source, commitment, and sum-check work can stay local to separate machines.
Prover and verifier map
| Responsibility | Prover | Verifier |
|---|---|---|
| Top-level schedule walk | akita-prover/src/protocol/prove/root.rs | akita-verifier/src/fold/verify.rs |
| Root and recursive fold orchestration | akita-prover/src/protocol/prove/fold/ | akita-verifier/src/fold/ |
| Extension-opening reduction | akita-cpu-backend/src/opaque/recursive/opening/ | akita-verifier/src/stages/opening_claims/extension_claim.rs |
| Stage 1 range and norm proof | akita-cpu-backend/src/opaque/sumcheck/digit_range/ and physical_l2_norm.rs | akita-verifier/src/stages/stage1.rs |
| Stage 2 fused relation | akita-cpu-backend/src/opaque/sumcheck/relation_range_image/ | akita-verifier/src/stages/stage2.rs |
| Stage 3 setup product | akita-cpu-backend/src/opaque/sumcheck/stage3/ | akita-verifier/src/stages/stage3.rs |
| Terminal path | akita-prover/src/protocol/prove/suffix.rs | akita-verifier/src/fold/terminal.rs and terminal/direct.rs |
The exact source layout can evolve, so begin with the public core entry points and follow the shared types they call. The Book's Verification child pages provide a value-by-value map of the current verifier calculations.
Review checklist for a fold change
Before accepting a change to this path, check all of the following:
- The generated schedule and proof shape still describe every message.
- Prover and verifier absorb public data and proof messages in the same order.
- Source, witness, relation, and challenge indexes use the same physical layout.
- Every relation row is interpreted in its scheduled native ring before lifting or batching.
- Stage 1 output and the incoming opening claim are both bound inside Stage 2.
- Stage 3 is present exactly on offloaded setup edges.
- The successor receives the exact witness and setup claims produced by its predecessor.
- Malformed sizes, encodings, schedules, and terminal values return an error on the verifier path rather than panicking.
A fold is not correct merely because its prover can produce a proof that its verifier accepts. Its schedule, transcript, relation layout, final oracle checks, and independent rejection tests must all describe the same statement.
Field-to-ring evaluation reduction
This page explains the first correctness obligation of an Akita opening: given the partial evaluations produced by the scheduled opening method, how do public weights recombine them into the scalar claim carried by the protocol?
Start with the base-field specialization
Here both the polynomial table and the opening point are defined over the base field . Akita commits the table through the cyclotomic ring
The schedule chooses one of two opening methods. EvaluationTrace keeps one
full element per live block and finishes the inner contraction
with TraceOpen. SubringCoefficientPacking contracts part of the inner axis
earlier and keeps a shorter polynomial over the opening field. In
both cases the result is a field-valued linear relation on the committed
opening digits:
| Opening method | Partial carried into the fold | Scalar target bound here |
|---|---|---|
EvaluationTrace | full-ring | the trace target; it equals in the base-field case |
SubringCoefficientPacking | shorter | the original extension-valued |
For a proper extension-field point, EvaluationTrace first uses
extension-opening reduction, or EOR, and
the derivation below applies to the reduced trace target. Coefficient packing
instead binds the original extension-valued opening directly. The
fold-path overview states where the schedule uses each
method.
The evaluation problem
Choose a ring dimension and a power-of-two number of positions per block. Re-index the polynomial table as
where:
- is an inner index that will become a ring coefficient;
- is a position inside a block; and
- is a block index.
Missing entries in a partial final block are public zeros.
Split the opening point in the same order:
Write the corresponding interpolation weights as
For a multilinear opening in the Lagrange basis, these are equality weights:
The evaluation claim is therefore
Akita evaluates the three axes in the order
Reduce to a ring-valued evaluation
Pack the inner axis into ring coefficients
For each position and block , pack the inner slice into a ring:
This is only a change of representation. The table entry becomes the coefficient of .
Equivalently, the values form a ring-valued multilinear table
This is the same underlying table under a lossless coefficient packing, not a new witness. The ring polynomial has fewer variables and is opened at
whose base-field coordinates act as constant elements of .
Evaluate the ring polynomial
First evaluate the position coordinate independently inside every block:
The coefficient of in is
Next evaluate the block coordinate:
Thus Equation (4) is the ring-based evaluation claim
Now
Thus contains the polynomial after evaluating the position and block parts of . Only the inner coordinate remains.
Pack the inner opening weights
Pack the remaining weights into a second ring:
The two rings have different sources:
| Ring | Derived from | Meaning |
|---|---|---|
| , , and | the polynomial after the two outer folds | |
| the weights for the remaining inner fold |
Using Equation (5), the original evaluation can already be written as
Recover the evaluation with TraceOpen
Let be the ring automorphism
For any , define
where denotes the constant coefficient in .
If
then the matching terms in are
They contribute to the constant coefficient, giving
Applying this definition to and using Equation (7),
Therefore:
TraceOpen is a coefficient pairing. It is not the univariate evaluation
used to reduce ring-valued relations to the field.
Eliminate the intermediate ring evaluation
Hachi: expose
The baseline Hachi protocol exposes and checks two statements:
and
The first statement proves that is the correct evaluation of the ring-valued polynomial. In this fold, each is digit-decomposed into the committed partial-evaluation witness:
where are the digit rings and are public gadget weights. Substituting this decomposition into Equation (12) gives
Equation (15) is a relation over the ring that enforces consistency between the ring element and the witness polynomials . Hachi sends to the verifier, which checks Equation (13) directly. The prover then proves Equation (15) using the same ring-relation machinery as the other constraints that bind the previous witness to the next witness, as described in Semantic relations in an Akita fold.
Akita: compose the two checks
Akita's crucial observation is that is already determined linearly by the
committed partial-evaluation witness and that
is itself a linear map. Sending would
therefore introduce a redundant ring element, an extra interface between the
two checks, and additional verifier work. Akita instead composes the two
linear maps and applies TraceOpen directly to Equation (15):
Write each digit ring as
and define the public inner trace weight
By linearity,
Equation (16) becomes the direct evaluation-consistency relation
In the base-field setting, Equation (9) gives
Thus every factor in Equation (18) has a simple role:
- recomposes the digit planes;
- evaluates across blocks; and
- evaluates inside the packed ring.
This row acts on the committed partial-evaluation digits . The other fold relations bind those digits back to the original committed polynomial.
The two possible protocol views are:
Expose Y:
committed ê ──recompose──> E_b ──block fold──> Y
│
TraceOpen
│
v
Eliminate Y:
committed ê ───────composed public linear map──────> v
Express the direct relation as a sumcheck claim
The committed fold witness is stored as one flat table . Flatten the indices into a Boolean address , and define the public weight function
Then Equation (18) is
This is the evaluation-correctness relation consumed by the later sumcheck protocol. It is already a field-valued linear relation on the committed witness. It therefore needs neither evaluation at nor a ring-switch quotient. This fact concerns only the scalar opening row. Quotient-free ring checking is a separate method for converting the physical ring equations into field claims. Those equations must still bind the partials to the committed source.
Subring coefficient packing: shorter partials
The evaluation-trace partial retains all inner coefficients. Subring coefficient packing shortens this partial by contracting one part of the inner axis before the opening digits are formed.
Return now to the general case in which the opening point lies in a field containing ; the interpolation weights , , and are then -valued. The case is included. Let
Choose a retained-axis dimension —later also the challenge-subring dimension—and write
Here is the packing factor. The implementation and specification call this value ; this page uses so that it cannot be confused with the opening-digit index already used in the evaluation-trace derivation. Every inner coefficient index has a unique form
Split the inner opening point in the same order:
The tensor-product interpolation weight therefore factors as
The index is contracted now; remains explicit. It helps to see this as a two-dimensional coefficient table rather than one flat list. For a fixed block , first apply the position weights and write
The rows are indexed by the coefficient that will remain in the packed partial. The columns are indexed by , which is consumed now:
| retained row | after contracting the row | ||||
|---|---|---|---|---|---|
The table is not a new witness. It is only a view of the position-folded source coefficients. Contracting one row gives
For example, take , , , and . Then , so the flat inner coefficients become two rows:
j = 0: ell = 0 1 2 3 -> e[b,0]
j = 1: ell = 4 5 6 7 -> e[b,1]
Each row is contracted to one element of the degree-two field . The packed partial therefore contains two elements of , or four base-field coordinates, instead of all eight source coefficients.
Substituting Equations (24) and (25) into the original multilinear evaluation gives
Thus the early contraction loses no part of the claimed evaluation. It only splits the old inner contraction into two stages: is consumed while the partial is formed, and is consumed in the final scalar relation.
Package the retained coefficients as
The ring has coefficients in . Fix the canonical -basis of and write
Consequently one packed partial has base-field coordinates, rather than the coordinates of . The basis elements are fixed by the canonical extension-field representation; they are not transcript challenges or schedule choices.
The next witness stores balanced digits of these base-field coordinates. Use for the opening-digit index:
Substituting Equations (28) and (29) into Equation (26) gives the direct packed opening relation
Read Equation (30) from the inside out. The opening gadget weights rebuild each base-field coordinate from its digits. The basis elements rebuild the extension-field coefficient . The tail weights consume the retained rows, and the block weights combine the live blocks. The result is the original scalar opening .
This is an -valued virtual row on the committed digit witness. It is not a ring-matrix row and has no cyclotomic quotient. Claim batching and Stage-2 row batching multiply the displayed weights by additional public scalars, without changing the single-claim identity.
At this scalar layer, the two methods have the same high-level output: a public linear map from the method-selected opening digits to the scalar target. They use different digit geometries and different public maps.
What scalar correctness does not prove
Equations (21) and (30) answer the scalar question under one assumption: the partials or are the correct partial evaluations of the incoming committed polynomial. The equations do not establish that assumption. A prover could otherwise choose unrelated partials that satisfy the scalar equation.
The next chapter supplies the missing source-consistency statement. Rather than check every block independently, Akita samples random fold challenges and batches the blockwise equations into one relation on the folded response . The two method-dependent shapes are
and
Semantic relations in an Akita fold derives both relations. In particular, it explains why the packing challenges must act only on the retained axis. Checking ring relations over a field comes later, after this semantic relation and its physical rows are established. Sumcheck stages explains how the method-selected scalar relation is row-batched and fused with the other Stage-2 terms.
Opening-method code reference
Evaluation trace
This subsection applies when the schedule selects EvaluationTrace. A fold
that selects SubringCoefficientPacking uses the coefficient-packing flow in
the following subsection instead.
The CPU backend performs the private opening arithmetic. The base-field path follows the reduction above:
- Prepare the opening weights.
prepare_opening_pointconstructs , , and . - Evaluate the ring polynomial.
evaluate_claims_at_prepared_pointreturns the position-folded rings and the temporary ring . - Recover the scalar evaluation.
scalar_opening_from_folded_ringcomputes . - Prepare the trace factors.
prepare_evaluation_trace_group_parametersprepares the block point underlying , the gadget weights , and the inner trace weights . - Construct the trace weights.
build_evaluation_trace_weightscombines those factors with the claim coefficients and physical locations to construct . - Fuse the Stage-2 relation.
accumulate_fused_relation_linear_signedadds the prepared linear relation to the fused Stage-2 sumcheck.
PreparedFold::relation_groups retains one method-selected point and the
scalar openings for each group as PreparedRelationGroupPublic metadata.
For evaluation trace, PreparedRelationGroupPublic::kind() gives the prepared
, , and factors. PreparedFold::witness_handle is an opaque handle
to the backend-owned digit witness. Protocol orchestration can use the public
weights but cannot inspect the private opening digits through that handle.
The main data flow is:
opening point r
|
v
PreparedOpeningPoint: weights Q_p, B_b, P
|
v
OpeningFoldOutput
|-- folded: [E_b] -- digit decomposition --> e_hat in witness w
`-- eval: Y ------- TraceOpen_P ----------> v_tr
|
v
PreparedFold
|-- evaluation_trace_claim: v_tr
|-- relation_groups: method-selected points and scalar openings
|-- evaluation_trace_claim_coefficients: c_q
`-- witness_handle: opaque backend-owned digit witness
|
v
prepare_evaluation_trace_group_parameters
|
`-- public factors B_b, G_h, J_l
|
v
build_evaluation_trace_weights
|
`-- T(x) on the committed e_hat segment
|
v
accumulate_fused_relation_linear
|
`-- Stage 2 proves v_tr = sum_x w(x) T(x)
In the base-field case, calling as_base() on
PreparedOpeningPoint::ring_multiplier_point returns Some(base_point).
The table uses base_point for the contained RingOpeningPoint reference.
The main values are:
| Code value | Mathematical object |
|---|---|
base_point.position_weights in the base-field case | |
base_point.live_block_weights in the base-field case | |
PreparedOpeningPoint::packed_inner_trusted() | |
OpeningFoldOutput::folded | |
OpeningFoldOutput::eval | temporary |
PreparedEvaluationTraceClaim::claimed_evaluation | |
PreparedEvaluationTraceClaim::claim_coefficients | claim-batching coefficients |
RingRelationGroupWitness::folded_opening, in its EvaluationTrace variant | position-folded rings |
RingRelationGroupWitness::e_hat | digit rings |
PreparedFold::evaluation_trace_claim | carried into Stage 2 |
PreparedFold::relation_groups, through PreparedRelationGroupPublic::kind() | prepared , , and for each evaluation-trace group |
PreparedFold::witness_handle | opaque handle to the backend-owned digit witness, including the opening digits |
PreparedFold::evaluation_trace_claim_coefficients | carried into trace-weight construction |
EvaluationTraceGroupParameters::shared_block_opening_point | block point from which is evaluated |
EvaluationTraceGroupParameters::opening_digit_weights | |
EvaluationTraceGroupParameters::shared_inner_trace | , equal to in the base-field case |
EvaluationTraceWeights |
The temporary ring is used only to compute ; it is not
stored in PreparedFold or sent to the verifier. Stage 2 instead proves
directly from the committed digit witness.
Subring coefficient packing
The implementation follows the same derivation in three stages:
- Prepare the point.
PreparedSubringCoefficientPackingPointchecks and prepares the packing, tail, position, and block weights. - Pack and bind the partials.
The prover contracts the and axes to obtain the coordinates
in
[block][extension coordinate][subring coefficient]order. It recombines those coordinates as in Equation (30), then binds their digit decompositions before sampling the fold challenges. - Fold and verify.
fold_coefficient_packing_groupfolds the packed partials and produces . Stage 2 then checks both the packing relation and the direct scalar opening, using to rebuild each extension-valued coefficient.
The reference tests in
coefficient_packing_fold_tests.rs
compare the direct partial and scalar formulas with the flat factorization.
The Stage-2 tests in
coefficient_packing_relation_tests.rs
check the expanded prover terms and that every extension-coordinate plane is
bound. The verifier tests in
coefficient_packing_relation/tests.rs
compare the compact evaluation with dense oracles built from those expanded
terms.
Base-field polynomial at an extension-field point
The scheduled opening method determines this case.
With EvaluationTrace, Akita does not treat a base-field multilinear
polynomial as an ordinary extension-valued opening of the same arity. It first
runs the extension-opening reduction. The
low variables are packed into extension-field
coefficients, and one degree-two tensor sumcheck reduces the original claim to
a claim on that packed polynomial with fewer variables. The reduced claim then
enters the evaluation trace. The trace represents its extension weights by
canonical subfield coordinates, and the verifier rejects invalid shapes,
coordinate counts, and noncanonical images before using them. Configurations
with skip this reduction.
With SubringCoefficientPacking, Akita keeps one coefficient axis in the
challenge subring, contracts the other axes over the extension field, and
binds the original scalar opening directly in Stage 2 without EOR. The
derivation is in Subring coefficient packing: shorter
partials; Fold path and field
geometry states the schedule boundary.
Semantic relations in an Akita fold
This page derives the semantic relations proved by one non-terminal Akita fold. The central question is the second correctness obligation from the previous page: are the method-selected partial evaluations consistent with the same incoming polynomial that is being folded?
The presentation starts with one polynomial group and one opening claim. The commitment relations use the ordinary source ring
The opening-consistency relation has two method-dependent geometries:
EvaluationTracekeeps a full ring partial and proves the relation in .SubringCoefficientPackingkeeps extension-field coefficients, proves the corresponding relation in the challenge subring, and embeds the same sparse challenge into for the source fold.
The other three semantic roles—inner-commitment, outer-commitment, and opening-commitment consistency—are unchanged by that choice.
The current implementation also supports more elaborate physical layouts. These include commitment groups, witness chunks, and different ordinary , , and ring dimensions. These extensions do not change the four core relations developed below. This page establishes only the basic case; advanced layouts are outside its scope. The advanced relation layouts page develops the multi-group case. The raw and compressed realizations use the same semantic relations; the compression realization introduces its own smaller ring dimensions.
The four families below are the semantic source relations. The current implementation realizes the and commitment relations either by transmitting their semantic commitments as raw payloads or by binding those commitments to smaller terminal payloads through compression relations. This choice changes their physical realization, not the four semantic constraints derived here.
The goal of the fold is to reduce the claims about the current polynomial blocks to an opening claim about a new digit witness. This is a reduction of the statement carried forward, not a guarantee that the complete next-level witness is smaller. The fold proves that the new witness is consistent with:
- the opening data computed from the old polynomial;
- the inner and outer commitments; and
- the random fold of the old polynomial blocks.
These statements form the semantic core of the physical ring relation. The scalar evaluation claim from Field-to-ring evaluation reduction is a separate field-valued relation. Each opening method supplies its own public linear map from opening digits to that scalar. This page instead proves the source-consistency relation that justifies those digits. The scalar row and physical rows are fused later.
Contents
Inputs and objects derived in the fold
A fold starts from a public opening claim
for a polynomial whose commitment payload is already fixed. We call the semantic commitment behind that payload. In raw mode, itself is transmitted; in compressed mode, the payload is the smaller terminal commitment , which is bound to by the compression relations on the realizations page.
The prover and verifier have different views of these inputs. The prover holds the polynomial blocks, their inner-digit representation, the commitment hint generated when the commitment was formed, and the public commitment payload. The verifier knows that payload and the opening claim, but receives neither the blocks nor the hint.
From these inputs, the current fold derives two new representations of the committed polynomial. The opening point determines partial evaluations inside each block, while fresh transcript challenges fold the old block digits into a response . Both are digit-decomposed before entering the next committed witness. The four relation families later prove that these derived objects are consistent with the same hidden opening of .
The committed polynomial and opening query
As in the previous page, split the ring-valued polynomial table into blocks. Let index a live block and a position inside that block. Pack the inner coefficient axis into the ring element
The field-to-ring evaluation
reduction splits into
inner, position, and block coordinates and defines their interpolation weights
, , and . We reuse those definitions here rather than
deriving them again. The position weights produce below, while the
block weights and inner weights belong to the field-valued
evaluation relation. The opening claim enters this page with target . An
EvaluationTrace fold later writes its reduced target as ;
a SubringCoefficientPacking fold binds the original scalar target directly.
For the single base-field claim considered here, the valid method-selected
target equals .
Balanced digit representations
Both the existing commitment opening and the next committed witness must have bounded coefficients. This shortness condition is what lets commitment binding reduce to Module-SIS: two distinct bounded openings of the same linear commitment would yield a short, nonzero kernel vector.
Akita obtains these bounded representations by decomposing ring coefficients into balanced base- digits. Let be an even power of two, let be the digit depth, and let . A balanced decomposition of consists of digit rings , indexed by and , such that
for every coefficient position . Stack the digit rings with innermost into . Define the gadget row and its block-diagonal recomposition matrix by
The coefficientwise identities then become the vector equation
The entries of are public scalars embedded as constant ring elements. Thus is a deterministic recomposition matrix, not a commitment matrix such as , , or . Digit decomposition produces ; multiplication by reconstructs . The protocol's range check certifies that the committed coefficients of lie in the balanced digit range.
Akita chooses separate bases and depths for different witness roles. To keep the derivation readable, write , , , and for the corresponding scalar gadget weights. The four recomposition identities used on this page are
The first two identities describe commitment-side data already fixed by the incoming commitment payload: is the incoming inner-digit representation, and is reconstructed from the incoming hint. The latter two digit families, and , are newly derived from the opening point and fold challenges. We now place each identity in its protocol context.
Polynomial blocks and commitment hint
The commitment-side inputs are fixed before the polynomial is queried. For each block, the prover has the inner digit rings and can therefore recompose the polynomial rings as
For one block, collect the digit rings into a vector . The inner commitment matrix maps this block vector to an inner image
Each coordinate of is itself represented by balanced outer digits:
where selects a row of . Stack these digits over all blocks to obtain . The outer commitment matrix then gives the semantic commitment
The two matrices have distinct roles: forms one inner image per block, whereas commits the digit-decomposed inner images across all blocks. The prover's commitment hint stores the recomposed inner images ; this fold decomposes them to recover . At a recursive level, the polynomial blocks, hint, and public payload were produced by the preceding level. At the root, they come from the original commitment. The semantic commitment fixes this commitment-side data. Equations (1)--(4) describe its hidden opening, which the later relation rows bind to .
Partial evaluations and opening digits
The first new witness object derived in this fold comes from the opening point. Use its position weights to evaluate the position coordinate inside each block. In the base-field setting of the previous page, acts as a constant in :
Digit-decompose each with the opening gadget weights :
The fold witness contains the digit rings , not a second copy of the recomposed . Their semantic opening commitment is
Here commits to the digit-decomposed partial evaluations.
Equations (5) to (7) show the EvaluationTrace shape, where each partial is a
full ring element. With SubringCoefficientPacking, the previous page instead
splits the source coefficient index as
contracts , and retains . The resulting partial is
Writing each -coefficient in the canonical basis gives base-field coordinates:
Thus the two methods create different opening-digit layouts, but in both cases binds the newly derived digits. The scalar derivation already showed how the packed coordinates recombine into the original opening claim. The next subsection proves that they came from the folded source.
The subscript in distinguishes this ring-vector commitment from the scalar opening target and its method-selected field relation. Equation (7) binds the newly derived opening digits; it does not by itself prove the scalar evaluation claim.
The folded response and its digitization
The semantic opening commitment commits the prover to . It does not by itself show that the corresponding partial evaluations were computed from the incoming polynomial blocks. That missing link is method-dependent.
Evaluation-trace consistency
For EvaluationTrace, correctness in every block requires
Equation (8) connects the partial evaluation derived in this fold to the incoming block witness . The semantic commitment creates a second consistency requirement. Equation (4), , binds the outer digits , which recompose the inner images through Equation (3). However, this commitment relation does not by itself show that the inner images were computed from the incoming block witness. The missing link is the blockwise relation from Equation (2).
Checking both relations separately for every live block would retain the block index in the next proof. Instead, after the public payloads binding and have been fixed, the transcript samples one sparse ring-valued challenge for each live block. These challenges are separate from the query weights . The prover folds the incoming block witnesses into one response:
The folded response no longer carries a live-block index. Because both blockwise relations are linear in , the same challenges batch them into relations on this single response. For the partial evaluations, Equations (8) and (9) give
For the inner commitments, Equations (2) and (9) give the vector relation
Equation (9a) says that evaluating within each block and then folding gives the same result as first folding the block witnesses into and then applying the evaluation weights. Equation (9b) similarly connects to the inner images bound through . If any blockwise relation is incorrect, its error is unlikely to disappear in the corresponding random combination. Thus the challenges remove the block index while preserving the two links from the incoming witness: one to the partial evaluations created in this fold, and one to the commitment that entered it.
Subring-coefficient-packing consistency
Recall the coefficient-table index split
Here (read "ell") is only the flat coefficient index in the A ring: selects a column and selects a row. The packed partial has already taken the same weighted sum across the columns of every row. It keeps the rows, so the fold challenge must act on those rows without mixing the already-contracted column axis. This is why it is sampled from
We use two linear maps. The first symbol below is (Greek "iota", not the index ). It embeds a row operation from into the source ring :
The second map, , is the public packing map from one source-block vector to . For any vector with the same shape as , define
Thus first recomposes the inner digits with , then contracts the position axis and the column axis , while leaving one output coefficient for every row . Together with the definition of above, Equation (1) gives . The intuition is now simple: moves rows, while compresses each row. For example, take , , , and . The source table has two rows of width four. In this picture, and already include the position sum over and the inner-digit recomposition over :
u = 0 1 2 3 after applying L
j = 0 a0 a1 a2 a3 ----------------------> e0
j = 1 b0 b1 b2 b3 ----------------------> e1
Both rows use the same packing weights, so
Since , multiplying in moves the first row to the second and wraps the second row back with a minus sign. Thus becomes . Applying after this move gives . Applying first gives , and multiplying by in gives the same result because :
Because any is a linear combination of these row shifts, the same commuting identity holds for every challenge:
The transcript draws one per live block and the prover forms
Linearity and Equation (9c) then give the packed source-consistency identity
The same embedded challenges are used in the inner-commitment identity . There is no second challenge draw for the A relation. This shared challenge is what makes the packed partial and the source fold describe the same random combination of blocks.
This compression has an arithmetic cost: combining the blocks increases
coefficient magnitudes. Let bound the coefficient norm of
every digit block , and let
, using itself for
EvaluationTrace and its sparse embedding for packing.
Negacyclic multiplication gives
where is the set of live blocks. The schedule fixes the challenge family, its relevant norm bounds, an admissible fold-response bound , and a digit depth large enough to represent the accepted response. The implementation may resample the transcript nonce until the resulting fits that scheduled bound. This grinding helps the honest prover find a compact response; the range check on its committed digits is what certifies the bound in the protocol.
Equations (9a), (9b), and (9e) are identities among recomposed values; they do not yet use the opening digits , the outer digits , or bounded digits for . The next-level committed witness contains digit rings rather than itself so that its shortness is certified for the Module-SIS binding argument. Akita therefore decomposes once more:
The three main digit segments assembled for the next witness are therefore
They have different origins:
| Segment | What it digit-decomposes | Why it is needed |
|---|---|---|
| the challenge-folded block digits | becomes the smaller folded response | |
| the position-folded rings | carries the opening data into the fold | |
| the inner images | binds the folded response to the existing commitment |
The four semantic relation families
Equation (11) specifies how the three digit segments are assembled, but it does not impose any algebraic relation among them. Substituting the balanced recompositions into the identities above gives two relations among the private witness segments. Equations (4) and (7) provide two additional relations that define the semantic commitments and computed by and , respectively. Together, these give four semantic roles. Three are ordinary ring relations over
The opening-consistency family is also over for EvaluationTrace; for
packing, it is over and is later realized through coordinate
planes. Vector equations are interpreted coordinatewise in their stated ring.
The first two families connect private witness segments to one another. The
last two define the semantic commitments and .
1. Fold-evaluation consistency
For EvaluationTrace, Equation (9a) is the fold-evaluation identity among the
recomposed values. Substitute the balanced digit representations of
from Equation (6) and from Equation (10) to obtain
This relation uses the random fold challenges , not the block-opening weights . The latter belong to the separate field-valued evaluation relation on . In particular, this ring relation does not contain the scalar target .
For SubringCoefficientPacking, substitute the packed opening-digit
recomposition and Equation (10) into Equation (9e):
The outer is essential: it reconstructs each coordinate separately before applies the position weights , the inner gadget weights , and the packing weights . Equivalently, the right-hand side is
This is the same semantic obligation in the smaller geometry: the packed partials on the left and the packed folded source on the right must agree. The expression is one logical -valued relation. Its physical realization uses extension-coordinate planes. The packed E/Q contributions enter the common relation-weight factorization, while the folded-source contribution is a separate packing-Z Stage-2 term. Together they realize one protocol claim, not independent claims.
2. Inner-commitment consistency
Equation (9b) is the inner-commitment identity among the recomposed values. The next-fold witness stores their balanced digits instead. Substitute Equation (3) for and Equation (10) for . For every row of , this gives
For packing, every in Equation (13) denotes the embedded element . Thus Equations (12b) and (13) use the same transcript challenge in their respective native geometries.
There is no factor on the right of Equation (13): already acts on the inner digit vector , whose columns are indexed by .
3. Outer-commitment consistency
The first two families compare private witness segments but do not yet define the commitment produced by the outer commitment matrix. The semantic outer-commitment relation is
Here , where is the output rank of . Equation (14) binds the private outer digits to the semantic commitment and does not use the fold challenges. In the raw realization, the prover proves this equation directly against the public . In the compressed realization, remains the semantic intermediate value: the prover recommits it through an chain and proves that the chain ends at the smaller public payload .
4. Opening-commitment consistency
Likewise, the semantic opening-commitment relation defines the commitment to the opening digits under :
Here , where is the output rank of . Equation (15) similarly binds the private opening digits to the semantic opening commitment . In the raw realization, the prover proves this equation directly against the public . In the compressed realization, remains the semantic intermediate value: the prover recommits it through an chain and proves that the chain ends at the smaller public payload .
The public value binding this relation is absorbed before the fold challenges are sampled: raw mode absorbs , whereas compressed mode absorbs . Together with the boundedness of and Module-SIS binding, this prevents the prover from adapting the partial-evaluation digits after learning those challenges. Like the other three families, Equation (15) is a ring-valued relation distinct from the field-valued scalar evaluation claim.
The four families above determine the algebraic constraints of a valid fold, but they do not yet determine which commitment values are transmitted, which additional witness segments are required, or which native-ring rows appear in the proved matrix relation. Raw and compressed realizations of an Akita fold makes those choices explicit while preserving the method-selected Equation (12a) or (12b) together with Equations (13)--(15) as their semantic source.
Raw and compressed payload realizations
Raw mode sends the semantic commitments themselves. Compressed mode binds those same commitments to smaller public payloads through additional private digits and ring equations. Both modes preserve the four semantic relation families.
This chapter explains which witness values, public targets, and physical rows each payload mode needs. A physical row is one coordinate equation in its stated ring. We first compare the two payloads, then derive the compression chains that connect them to the semantic commitments.
Compression here concerns public commitment payloads, not the complete next-level witness. Smaller payloads require additional private digits to prove their compression chains. The complete recursive witness also includes response, opening, and inner-commitment digits, plus any quotients required by the relation mode. A shorter folded response therefore does not guarantee a smaller complete witness; the root may expand it while reducing the relations to one recursive witness opening claim.
The output is a set of ring equations. Checking ring relations over a field explains the next step: use either quotient lifting or quotient-free checking to turn those equations into field claims for Stage 2. The opening method remains a separate choice. It determines the partial-evaluation geometry in either payload mode.
Contents
- From semantic relations to physical realizations
- Commitment compression realization
- From physical rows to field checks
- The scalar opening claim is a method-dependent virtual row
- Code reference
From semantic relations to physical realizations
The four relations derived on the previous page are semantic: they state which algebraic constraints a valid fold must satisfy, without prescribing which commitment values are sent in the proof. A physical realization turns those constraints into the native-ring matrix equations used by a particular payload mode. It determines the public payload, any additional compression witness, and the right-hand side of each equation.
When these equations are assembled as a matrix, each coordinate equation is a physical row. For example, the vector equation contributes physical rows, one for each coordinate of . A physical row is therefore an individual native-ring equation implementing a semantic relation, not a new semantic claim.
Only the two commitment relations depend on the payload-mode choice. Their semantic values are
The fold-evaluation and inner-commitment relations have the same physical form in raw and compressed payload modes. Their form may still differ between the two opening methods.
Raw realization
In raw mode, the public payload is the semantic commitment. The prover computes and and transmits their complete ring vectors. They appear directly as the right-hand sides of the ordinary and rows:
The logical witness contains only the three segments already used by the four semantic relations:
For the basic EvaluationTrace geometry, writing the four row families as one
conceptual matrix gives
Let , , and denote the row counts of , , and . In that one-group layout, the raw realization has physical rows:
| Physical rows | Count | Meaning | Right-hand side |
|---|---|---|---|
consistency | Equation (12a) | ||
| rows | Equation (13) | ||
| rows | Equation (14) | ||
| rows | Equation (15) |
Consequently,
The verifier therefore receives the values defined by the semantic relations and places them directly in the raw relation instance. No compression digits or rows are present. The matrix need not be materialized densely: its entries are generated from the fold challenges, opening weights, gadget weights, and the setup matrices , , and .
With SubringCoefficientPacking, raw mode still transmits the same semantic
and commitments, but Equation (12b) is realized by
the packed coordinate-plane
relation.
It therefore does not reuse the single ordinary consistency row counted in this example.
Equation (17) is still a relation in the native cyclotomic ring; it is not yet the exact field identity consumed by sumcheck. The next chapter, Checking ring relations over a field, explains the two schedule-selected ways to obtain that field claim. We first finish defining the physical rows for compressed payloads.
Compressed realization
In compressed mode, the prover still computes the same semantic commitments, but does not transmit or . Instead, it decomposes each one, recommits the resulting blocks through a two-map chain, and sends one fixed 128-byte terminal payload for each chain. In the illustrative q128 example developed below, this replaces a 1024-byte semantic outer commitment by the 128-byte payload . The two commitment relations follow parallel chains:
The prover stores the two layers of and compression digits as additional private witness coordinates. These arrows are not a decoding procedure: the verifier does not recover from or from . Instead, additional equations, represented by physical rows, prove that the hidden semantic commitments recompose from the first digit layer and that the two compression maps lead to the transmitted terminal payloads. The and right-hand sides are therefore zero in compressed mode; and appear only on the terminal and rows.
From the verifier's perspective, the schedule already determines the payload mode. For a raw level, it assembles the ordinary relation right-hand side from and . For a compressed level, it assembles the larger row layout from and and verifies the compression chains together with the ordinary relations. The proof does not carry a separate mode tag.
| View | Raw realization | Compressed realization |
|---|---|---|
| Public payload | ||
| Compression-digit witness | none | |
| right-hand sides | zero | |
| Additional compression rows | none | |
| What binds the payload | the ordinary commitment equations directly | the ordinary equations followed by the compression chains |
Planner-selected realization transition
Compression saves public payload bytes but adds digit witnesses, relation rows, and restricted range-check work. With quotient lifting, its additional rows also add quotient witnesses. The planner prices both sides of this tradeoff for the complete recursive schedule; it does not choose a mode from the payload size alone.
Commitment groups created separately before recursive proving—for example, groups later supplied as precommitted root inputs—always use compressed payloads and are not part of the recursive mode choice. The protocol also requires compressed payloads for the root fold and the first recursive fold, when that fold exists. Any later fold that consumes a setup prefix must likewise remain compressed. At a later level that does not consume a setup prefix, the planner may either continue the compressed prefix or begin a raw suffix. Once it selects raw mode, every later recursive level remains raw:
The prefix length is schedule-dependent. Some current generated schedules cut over immediately after the required first recursive fold, whereas deeper recursive schedules keep several early recursive levels compressed. Thus "root and early folds are compressed" describes a planner-selected prefix, not a globally fixed transition point.
The next section expands the two commitment relations into their compressed physical rows.
Commitment compression realization
The outer-commitment and opening-commitment semantic relations, Equations (14) and (15), have the same structure: a commitment matrix maps a short witness to a semantic commitment consisting of a vector of ring elements. The raw realization places that complete commitment in the proof. The compressed realization instead recommits it using rank-one matrices over progressively smaller rings, producing a commitment chain whose terminal payload is exactly 128 bytes.
Why recommit?
The serialized size of an uncompressed semantic outer commitment is
where is the ring dimension and is the canonical byte width of one field element. In the q128 profile, one field element occupies 16 bytes. For a simple rank-one example, take and . Its uncompressed payload then occupies
The goal of commitment compression is to recommit this value in a smaller ring and repeat the process until the public payload has the desired size. This reduces the bytes occupied by the public commitment payload, but it also introduces new witness coordinates and relation rows. The planner accounts for both effects when it chooses between compressed and raw recursive payloads.
One recommitment step
At a high level, one step does not map a large-ring element directly into a smaller quotient ring. It first applies the balanced decomposition introduced above with base , whose digit range is . It then groups those digits into short coefficient blocks, each representing an element of the smaller ring. A rank-one setup matrix over that same smaller ring commits the resulting vector to one new ring element. The recomposition identity is the bridge from these smaller-ring blocks back to the original large-ring element.
For intuition, first suppose that the semantic commitment is a single ring element
The first operation is a coefficientwise balanced base- decomposition. For each , choose digits such that
where is the field-modulus bit width. Put the -th digit of every coefficient into one digit polynomial
Then
so every coefficient of every decomposed polynomial is either or .
The second operation repacks these digits into a smaller ring. Choose and divide the length- coefficient vector of each into consecutive blocks of length . The -th block becomes the coefficient vector of
Equivalently, if denotes the canonical degree-less-than- representative of this small-ring element, then
Collect all of the small-ring blocks into a vector
Akita uses bit-major order: all coefficient blocks for one bit position are contiguous before the blocks for the next bit position. In this unpadded single-element example, the vector has width over .
The fixed recomposition map restores both the coefficient positions and the powers of two:
This is the bridge between and . It is a fixed -linear coefficient-recomposition map, not a ring embedding or a homomorphism between the two quotient rings.
Finally, a rank-one matrix over the smaller ring recommits the packed blocks:
Together, the two equalities
link the original commitment in to a new commitment in through the shared digit vector . Conceptually, one recommitment step therefore performs three operations: decompose the source coefficients, repack the digits as small-ring elements, and commit those elements to one small-ring image.
The two-map commitment chains
The smaller ring cannot be chosen solely to minimize the payload. Decreasing its dimension makes the output shorter, but it also increases the number of input columns presented to the rank-one compression matrix. The pair consisting of the ring dimension and input width must remain within Akita's Module-SIS security bounds.
The current protocol therefore uses a fixed, profile-specific ladder of exactly two certified rank-one maps. The ladder accepts a complete source of at most 8 KiB and terminates at exactly 128 bytes.
For the semantic commitment , flatten its ring coordinates into field coefficients. Balanced base- decomposition produces digits in . Pack these digits in bit-major order into elements of , filling any unused coefficients of the last element with zero. These smaller-ring elements form . The first rank-one map commits this vector to ; the second layer repeats the same decomposition, repacking, and recommitment at dimension :
From the prover's perspective, the chain consists of five concrete steps:
- Compute the semantic commitment
- Decompose and repack into so that
- Apply the first rank-one map:
- Decompose and repack into so that
- Apply the terminal rank-one map:
Only is transmitted. The semantic commitment is computed but omitted from the compressed payload. The intermediate image is also not transmitted and is not stored as an independent witness segment; the two digit vectors and are the additional witness material. The physical relations in the next subsection bind this private chain all the way back to . The opening-side chain applies the same five steps to and terminates at .
The production compression dimensions are fixed by the modulus profile:
| Profile | First ring | First image | Terminal ring | Terminal payload |
|---|---|---|---|---|
| q128 | 256 bytes | 128 bytes | ||
| q64 | 256 bytes | 128 bytes | ||
| q32 | 256 bytes | 128 bytes |
For the q128 example above, the complete chain is
The widths count the small-ring elements needed to hold all balanced base- digits: and .
The schedule's payload mode determines whether these chains are present at a particular recursive level, according to the planner-selected transition described above.
Additional physical relations and witness
The equalities in a compression chain do not all live in the same ring. Each physical row is interpreted in the native ring displayed beside it, and each is the fixed linear coefficient-recomposition map defined above. Suppressing component indices inside that map, the outer chain gives three physical relation equations. Their labels extend Equation (14) to emphasize that the entire chain realizes that one semantic commitment relation:
The first equation is the compressed realization of the existing rows; the latter two add the rank-one and rows. The semantic opening commitment follows the same construction, with an chain:
For the basic one-group EvaluationTrace case, compressed mode therefore has
physical rows:
| Physical rows | Count | Right-hand side |
|---|---|---|
consistency | ||
For packing, the payload-mode suffix is identical, but the method-specific
coordinate-plane relations replace the ordinary consistency row just as in
raw mode.
Before adding quotient digits and alignment, the logical compressed witness has the following layer order:
The restricted check on the compression digits is described with the Stage 2 sumcheck. It is separate from the physical ring equations above.
From physical rows to field checks
Both payload modes now supply physical ring equations. Raw mode uses the public and as targets. Compressed mode uses zero targets for the intermediate relations and the public for the final compression rows. Each row keeps the native ring defined above.
The next step is to check those equations over a field. The schedule selects one of two methods:
- Quotient lifting adds private quotient digits that record reduction by each row's ring modulus.
- Reduced evaluation includes that reduction in public coefficient weights and adds no quotient digits.
The next chapter derives both methods from one ring equation. Only then does it combine them with raw and compressed payloads to give the complete witness layouts. This keeps the payload choice separate from the method used to check its rows.
The scalar opening claim is a method-dependent virtual row
Two different statements involve , and they should not be conflated:
| Statement | Form | Physical ring row? | Ring-switch quotient? |
|---|---|---|---|
| opening commitment | yes | only in QuotientLift | |
| evaluation correctness | no | no |
The scheduled opening method prepares the second statement. EvaluationTrace
uses the trace weight derived in Field-to-ring evaluation
reduction.
SubringCoefficientPacking uses the direct packed scalar
row.
The direct scalar opening in either method reuses the same row-batching
challenge . It is absent from the physical ring-row layout and its
public right-hand side. Thus it needs no ring-switch quotient in either
relation mode. Coefficient packing also has a physical source-consistency
relation, derived in Root fold and ring
switching.
After the physical ring rows become field claims, Stage 2 fuses them with this scalar opening and the range-image binding in one sumcheck.
Code reference
The implementation follows the same semantic relations in both payload modes, then selects different public right-hand sides and witness suffixes. The functions below also support multiple groups, chunks, and role-specific ring dimensions; in the basic setting they reduce to the construction on this page.
Prover flow
- Create and retain the commitment-side material. The standalone/root
commitment paths in
commitment APIcompute the semantic outer commitment and compress it. The recursivecommit_witnesscomputes the same semantic value, then follows the payload mode selected for that level. A raw recursive level exposes directly. A compressed commitment passes it toexecute_compression_chains, exposes only , and retains the two packed digit layers in the commitment hint. It retains their quotient rows when the consuming fold uses quotient lifting. - Build the fold-side objects.
RingRelationProver::preparecoordinates public opening payloads and fold challenges. The CPU backend decomposes the position-folded values into , computes , and retains the accepted response behind a fold handle. In compressed mode,materialize_compression_witnesscombines the retained material with a newly computed chain for , producing the terminal payload and storing both chains asCompressionWitnessMaterialization. - Assemble the mode-selected public statement. Raw mode calls
assemble_relation_rhswith and . Compressed mode instead callsassemble_compressed_relation_rhswith and . The latter emits zero ordinary and first-map right-hand sides, followed by the terminal payloads on the rows. - Construct the committed relation witness.
cpu_recursive_witness_buildderives from the semantic inner rows stored in the hint, and emits , , and . In quotient-lift mode it invokescompute_multi_group_relation_quotientto compute one quotient in every physical row's native ring. In compressed mode it also emits the two digit layers. In reduced mode it dispatches before quotient construction and uses negacyclic-only D and compression products.WitnessLayoutdetermines which ranges and alignment are live. - Prepare the Stage 2 relation evaluators. Quotient lifting uses the
factored
build_relation_lane_weightspath for theconsistency, , , and contributions. It accumulates one weight per relation coefficient lane; the shared low alpha factor stays implicit. Reduced evaluation builds one dense Stage-2 weight oracle instead. Both paths take their relation addresses from the semantic compiler inopaque/relation_weights/compiler.rs. Compressed mode additionally usesbuild_compression_relation_weightsor its reduced counterpart for the recomposition, , and mode-selected compression-quotient contributions, whileNegativeBinarySupportrestricts the separate check to the compression-digit spans. The scheduled opening method contributes separate -weighted Stage-2 terms after the payload-mode relation terms.
The mode split can be summarized as follows:
semantic inner rows
|
v
derive t_hat and u = B t_hat
|
+---------------- raw ----------------> public u
|
`-- compressed --> F chain ----------> public p_F
|
`--> retained F digits
position-folded values E_b
|
v
e_hat and v_D = D e_hat
|
+---------------- raw ----------------> public v_D
|
`-- compressed --> H chain ----------> public p_H
raw: assemble_relation_rhs(u, v_D)
compressed: assemble_compressed_relation_rhs(p_F, p_H)
|
v
RingRelationInstance + prover witness
|
v
cpu_recursive_witness_build
| |
quotient lift reduced evaluation
add R digits no R digits
|
v
factored or dense relation evaluator
+ optional compression evaluator
+ optional {-1, 0} support evaluator
+ method-selected opening terms
|
v
Stage 2
Public statement: RingRelationInstance
RingRelationInstance
is the common relation-statement carrier constructed independently by the
prover and verifier. Its public fields are verifier-reconstructible. In
compressed mode, private commitment intermediates remain inside the CPU backend:
| Field or accessor | Mathematical meaning |
|---|---|
group_ambient_a_challenges(0) | fold challenges in the A ring; embedded from the challenge subring for packing |
group_ring_multiplier_point(0) | ring multipliers used by the physical consistency row |
opening_batch() | authenticated group and claim geometry |
role_dims() | native ring dimensions |
rhs() in raw mode | in the basic setting |
rhs() in compressed mode | zero ordinary and first-map targets, followed by terminal targets |
Raw replay includes the public in rhs(). Compressed replay
uses instead; the privately computed remains in the CPU
witness-build state and is not a field of the public relation instance.
Full opening points are not owned by RingRelationInstance. They are prepared
separately by the scheduled opening method. The verifier consumes evaluation
trace points through
evaluation_trace.rs
and coefficient-packing points through its compact packing relation path. Only
the projections needed by the physical consistency relation remain in this
instance.
CPU-private relation witness state
The CPU consumer's private
RingRelationWitness
is the aggregate used while constructing an opaque CpuWitnessHandle; protocol
orchestration cannot inspect or transport it. In the basic setting, its private
groups vector contains one RingRelationGroupWitness:
| Field | Mathematical meaning |
|---|---|
fold | accepted CPU fold handle retaining the centered response coefficients and its challenges |
folded_opening | method-selected opening state: the rings for evaluation trace, or the packed fold product for coefficient packing |
e_hat | opening digits |
inner_relation | retained semantic inner rows used to reconstruct |
role_dims | native A, B, and D dimensions for the group |
The
PortableCommitmentHandle
does not store a materialized or a separate copy of
. cpu_recursive_witness_build derives from its semantic
inner rows. At the aggregate level, RingRelationWitness::compression holds
the optional materialized chains used by this fold.
RingRelationWitness::d_quotients records whether the shared D relation has
quotient data. Quotient-lift assembly includes ordinary and compression
quotient digits. Reduced evaluation places only the ordinary and optional
compression digits. WitnessLayout defines their exact ranges.
Verifier reconstruction
The verifier does not receive a serialized RingRelationInstance or any
RingRelationWitness. In
verify_fold,
it reconstructs the public instance from the schedule-selected payload and
transcript data, then calls
ring_switch_verifier:
schedule-selected payload mode
|
+------+------+
| |
raw compressed
u, v_D p_F, p_H
| |
assemble_relation_rhs
assemble_compressed_relation_rhs
| |
+------+------+
|
RingRelationInstance::new
|
authenticated relation mode
| |
quotient lift reduced evaluation
quotient tail terminal residue kernels
common alpha fused direct setup scan
| |
+----------+----------+
|
optional compact F/H evaluator
+ optional {-1, 0} support evaluator
|
Stage 2 verifier
Compressed replay deliberately sets RingRelationInstance::v() to an empty
carrier: the zero rows and terminal row are already encoded
in the compressed right-hand side. The separate method-selected opening
preparation retains the full point data needed to bind the claimed evaluation.
Opening points and digit-innermost
layout describes the canonical
physical source and witness order.
Checking ring relations over a field
A fold has already produced the physical ring equations that connect its witness to the commitment payloads. This chapter explains how Akita turns those equations into field claims for sumcheck.
The difficulty is ring multiplication. In , a term becomes . Ordinary polynomial evaluation does not apply that rule. Akita has two ways to include its effect in the field check:
| Method | Main idea | Effect on the witness |
|---|---|---|
| Quotient lifting | Record the reduction in a private quotient polynomial | Add its digits to the next witness |
Quotient-free checking, called ReducedEvaluation in code | Include the reduction in public weights on the existing coefficients | Add no quotient digits |
Both methods check the same ring equations. Raw or compressed payloads determine which physical equations exist. The ring-relation mode determines how to check them. We first explain both methods for one equation, then apply them to the complete fold.
Contents
- Why ordinary evaluation is not enough
- Quotient lifting
- Quotient-free checking by reduced evaluation
- From one equation to the full relation
- What enters the next witness
- Costs and current schedule choices
- Code reference
Why ordinary evaluation is not enough
Consider one relation
where is a public multiplier, is private, and is a public target. Use the same letters for their canonical polynomial representatives. Each representative has degree less than .
Write for the remainder of a polynomial after division by . Equation (1) says
For example, let , , and . Their ordinary product is . Their ring product is , because in . Thus is the correct target. At a general field point , however,
The missing step is the reduction. To account for reduction modulo means to include each replacement in the field check. This replacement is also called a signed wrap. Multiplication with this rule is called negacyclic multiplication.
The evaluation point lies in the protocol's challenge field , which contains . It need not be a root of .
Quotient lifting
Quotient lifting keeps ordinary polynomial multiplication and adds the missing reduction explicitly. Equation (1) holds exactly when a quotient satisfies
The canonical representatives determine this quotient uniquely. It has degree less than . In the example, , because
The quotient is private because it depends on . The prover decomposes it into bounded digit polynomials using public gadget weights :
Here is the quotient digit depth. These digits join the next witness. After that witness is bound, the transcript samples . The field check is
The modulus factor multiplies the quotient contribution. This check does not divide by that factor.
To see the public weights, write . Then
The weight factors into one multiplier evaluation and one coefficient power. The quotient digits have weights . If is also stored through digits, substitute its public gadget recomposition as well. The entire check is linear in the committed digits.
Fixing the witness before is essential. For a false ring equation, no allowed quotient can make Equation (2) a polynomial identity. Once the witness and quotient are fixed, its nonzero polynomial residual has only a bounded number of roots. Random evaluation detects that residual except when is one of those roots. This is the algebraic check; commitment binding and the later sumcheck must still bind it to the same witness.
Quotient-free checking by reduced evaluation
Reduced evaluation applies the signed wrap before evaluating at . It uses the fact that multiplication by a public is linear in the private coefficients :
Define the public weight for coefficient by
This list of weights is called the residue kernel. The superscript records the native ring dimension. Evaluating the reduced equation now gives
Every weight is public. There is no private quotient to commit, range-check, or carry into later folds.
In the same example, and the only nonzero coefficient of is . Its weight is
Equation (7) therefore checks directly.
Why this is transpose-convolution
Let be the public matrix that multiplies a coefficient vector by with signed wraparound. Let be the coefficient vector of and let . Multiplication followed by evaluation is
The vector is exactly the residue kernel. This explains the name transpose-convolution: transpose the public multiplication map onto the evaluation weights. The implementation computes these weights without building .
The reduction correction has not disappeared. For each public basis product, write
The polynomial is public because and are public. Hence
The same correction that quotient lifting stores through private digits is already part of the public coefficient weights in Equation (7).
Compute the weights in linear time
Write . Expanding Equation (6) gives
This formula shows every signed wrap, but computing it separately for all takes quadratic work. A recurrence avoids that cost.
The first weight is . To get the next reduced basis product, multiply the current one by . Its top coefficient crosses the modulus boundary. Ordinary evaluation would give for that term. The ring requires instead. Subtracting their difference gives
For in , the first step is , as required. All weights for one multiplier take field operations. The recurrence uses no division, so it also works when .
Here soundness concerns the reduced residual . Fix the witness, public multiplier, and target before sampling . A false ring equation gives a nonzero of degree at most . For an ideal uniform challenge ,
This follows because a nonzero polynomial has at most its degree many roots. Random evaluation checks the reduced residual, rather than the unreduced product with its quotient term removed. The full relation also needs the row-batching bound below.
From one equation to the full relation
Both methods extend by linearity to a row with several public multipliers. For one native dimension , write its ordinary product sum as and its target as . The index selects a term in row . Each uses the coefficient slice required by that row's layout. The ring claim is .
Quotient lifting checks
Reduced evaluation instead checks
where is coefficient of the row's witness term. It uses , not a kernel for a larger storage ring. In either method, the resulting row is a scalar claim over . The public multipliers, targets, layout, and witness are fixed before ; the coefficient weights are then derived from that challenge.
For EvaluationTrace, the consistency and rows use the native A
dimension. The and rows use their own dimensions.
Compressed payloads also add rows in the native ring of
each compression map. Fixed coefficient-recomposition terms keep the source
positions defined by the payload relation. They do not change into ring
embeddings between these dimensions.
SubringCoefficientPacking has a separate consistency geometry. Its logical
relation is in and uses coordinate planes of
length . In the current implementation it uses quotient lifting. Its
modulus factor is , even though the stored planes have total
width . The packing derivation
explains how its E/Q terms and folded-source term jointly realize that one
claim.
Batch the rows and hand them to Stage 2
Express each evaluated row in the stored digits. Let be the complete flat digit-witness table. Its address ranges over a padded Boolean domain . Each evaluated row has public coefficient weights such that
To construct , use the physical address of each stored digit from
WitnessLayout. Add that digit's public weight, including its gadget
recomposition factor, at the corresponding address. If several terms use the
same digit, add their weights at that address. The witness stores the digit
once; each use contributes to its coefficient in the row.
In quotient-lift mode, includes the quotient digits and includes their negative modulus factors. In reduced mode, includes the signed wraps and has no quotient coordinates.
The transcript samples the row point . Define the row weights and the combined public function
Both methods therefore supply the same form of field claim:
This combines all physical rows. The Stage 2 derivation separates their ordinary and compression contributions for efficient evaluation. It also adds the range-image binding and the scalar opening claim. Sumcheck reduces the combined claim to an opening of the same witness at its final point . The next fold authenticates that opening.
The three random objects have different jobs: evaluates the ring variable, batches rows, and addresses the flat witness. Range checking remains necessary in both modes. The ring relation checks algebraic consistency; the range check certifies small witness digits.
The EvaluationTrace scalar row is already a field-valued claim. It needs no ring-switch quotient in either mode. This is distinct from using residue kernels to check the physical ring rows without quotients. In particular, is still a physical ring relation.
Algebraic error after row batching
Row batching adds one more way for a false relation to pass: nonzero row errors can cancel at the sampled row point. We bound that event separately from the ring evaluation.
For reduced evaluation, let and . Condition on all witness values, public row data, and layout being fixed before . If any ring row is false, choose one nonzero . The probability that every vanishes is at most , since that event requires the chosen row to vanish.
Now fix and the resulting row residuals before sampling . Let be the number of coordinates of . Pad the physical-row residual table with zeros to its row addresses. If the table is nonzero, its multilinear extension
is nonzero and has total degree at most . For a fresh uniform , it vanishes with probability at most . Thus, for independent uniform and , a false collection of ring rows passes these two algebraic checks with probability at most
This bound covers only reduced ring evaluation and physical-row batching. It assumes the witness is already fixed. Commitment binding and extraction, the later sumchecks, and Fiat-Shamir challenge generation with transcript grinding require their own security arguments. The formula is not a soundness bound for the complete non-interactive proof.
What enters the next witness
The two choices now combine without changing their roles. Payload mode determines the commitment rows and compression digits. Relation mode determines whether those rows also need quotient digits.
| Payload | Quotient lifting | Reduced evaluation |
|---|---|---|
| raw | and ordinary quotient digits | |
| compressed | , compression digits, ordinary quotients, and compression quotients | and compression digits |
In the basic one-group EvaluationTrace layout, write
for the quotient digits of the consistency,
, , and rows, in that order. Quotient
lifting gives the raw witness
For compressed payloads, retain the notation and for the two chains' compression digits at layer . Write and for that layer's quotient digits. The physical order, with alignment ranges suppressed, is
Reduced evaluation removes every segment from these layouts.
It keeps the compression digits and their restricted check when
the payload is compressed. WitnessLayout derives the live ranges and any
required alignment for the selected mode. Missing quotients have no placeholder
coordinates. They contribute no range-check work or successor commitment
input. On multi-chunk folds, both payload modes align each chunk's Z/E/T body
to the successor's source-block boundary. The semantic T range ends before
the alignment gap. The canonical prover zero fills these gaps; verification
allows in-range filler, subject to all later response checks, as described in
alignment coordinates.
Single-chunk folds keep the contiguous, unpadded Z/E/T body.
For coefficient packing, the shared ordinary quotient segment includes the consistency-row slot for the digit-decomposed coordinate planes of . It has no separate method-specific quotient span. The witness-order page gives the group, chunk, and coefficient order used by both sides.
Costs and current schedule choices
Quotient lifting gives the simple weights in Equation (5). The prover can keep a factored relation representation. Its cost includes computing the quotients and carrying their digits through commitment, range checking, Stage 2, and later folds.
Reduced evaluation removes that witness material. Its public weights are more involved. The recurrence makes one multiplier's kernel linear in its native dimension, but this is not a bound on the whole fold. The current prover builds one temporary dense Stage-2 relation-weight table. Sumcheck folds that table; the proof neither commits nor serializes it.
The verifier uses a different calculation. At the final sumcheck point it prepares compact weights for each required native coefficient window. It then uses the existing combined A/B/D setup scan. It does not build the prover's dense table. Matrix evaluation at a point derives this calculation. Compression F/H maps are evaluated separately.
This explains the tradeoff across recursion. Large early folds benefit from factored weights. In smaller later folds, quotient digits can form a larger share of the next witness. Removing them can reduce later work. These facts do not give a universal runtime winner or a fixed transition level.
Setup offloading is a separate choice. It replaces a direct public-setup scan with Stage 3 and a setup-prefix opening carried to the next fold. Quotient lifting supplies the factored weights used by the current offloading path. The offloading chapter explains that handoff.
The current schedule permits ReducedEvaluation only at single-chunk folds
at level 2 or later. The first two folds and every multi-chunk fold require
coefficient packing and quotient lift.
The selected fold and every later nonterminal fold must use EvaluationTrace,
consume no incoming setup prefix, and perform setup evaluation directly.
Once the schedule switches, it cannot return to quotient lifting. The suffix
can use raw or compressed payloads, subject to the separate payload rules.
Coefficient-packing folds remain quotient-lift-only.
These are implementation restrictions. They do not show that other algebraic combinations are impossible. The schedule binds the mode before the next-witness binding and ; the proof carries no extra mode tag or challenge. The terminal fold has no ring-relation mode. It checks its clear response directly instead of producing another committed witness.
On an ordinary recursive edge, the outgoing binding is the next witness's commitment payload. On the last edge, it consists of the successor's inner commitment images. Both are fixed before the predecessor samples . The last edge does not add a duplicate outer commitment payload.
Code reference
ring_relation_mode.rsdefines both modes and the allowed transition.FoldSchedule::validate_structureenforces the complete schedule restrictions.witness_build/finalize.rsconstructs the mode-selected witness inside the CPU backend. Reduced evaluation branches before quotient construction.WitnessLayoutowns the actual ranges.ring_switch.rssamples after the caller binds the outgoing witness. The CPU backend'srelation_weights/stage2.rsthen selects factored or dense relation weights for Stage 2.ring/residue.rsimplements the recurrence. Its tests compare the result with explicit signed multiplication and ring products, including points where .relation/evaluation.rsselects the verifier calculation from the authenticated mode. Reduced mode uses the complete coefficient functional and rejects deferred setup.
The CPU relation tests check that raw and compressed reduced witnesses avoid quotient construction. The schedule tests check the transition, opening-method, and setup-prefix restrictions.
Advanced relation layouts
The semantic relations in an Akita fold start with one commitment group, one witness chunk, and one common ring dimension, while the realizations page turns those relations into physical rows. This page develops three independent extensions: multiple commitment groups, multiple witness chunks, and mixed commitment-ring dimensions. All three preserve the four semantic relation families. Multiple groups add group-local rows around one level-owned D relation, multiple chunks divide one group's witness columns across block ranges without duplicating those rows, and mixed rings assign each row family its role-native dimension.
The physical opening-commitment relation remains distinct from the field-valued evaluation trace. Each section isolates one extension under its own simplifying assumptions before explaining how it composes with the other axes.
Contents
Multiple commitment groups
Why multiple commitment groups
In zkVM applications, polynomials such as execution traces, advice, and preprocessed data may be committed at different times. When one commitment is formed, the prover may not yet know which other commitments it will later be opened with, the opening point, or the root schedule that will combine them. Akita calls the polynomials held under one independently formed outer commitment a commitment group. The layout associates one complete opening point with each group, shared by all claims in that group. Different groups may be opened at different points. One group is the final/new group, while commitments formed earlier enter as precommitted groups with already-fixed parameters.
Proving each commitment group separately would repeat the entire recursive
opening protocol. Akita instead batches the groups in one root transition and
then resumes the ordinary single-opening recursion. The batching preserves
the separate group commitments and folded responses: each group has its own
, , and group-local consistency | A | B
relations. On the opening side, however, every group contributes an
segment to one logically concatenated vector. One
matrix binds that entire vector, and the field-level evaluation
trace separately batches the claimed evaluations at their group-local points.
Group-local folded responses and relations
To isolate the group axis, assume one witness chunk, one common ring dimension, and one polynomial claim per group, then add a group index to the previous notation. Group has its own blocks , fold challenges , and folded response
There is no sum over : the folded responses remain separate. The basic consistency, , and relations are repeated independently for every group. In the semantic relation, the rows bind to that group's outer commitment . Each group also produces opening digits , which become one segment of the shared opening vector.
The fold and outer-commitment parts remain group-local because each commitment fixes its own and matrices, decomposition parameters, and semantic target . Its folded response is formed with that group's challenges and must be checked against those fixed parameters. Combining the responses across groups would lose these group-specific commitment bindings.
The shared opening-commitment relation
The relation can be shared for a different reason. Unlike and , is owned by the fold level rather than by an individual commitment group. Every segment uses the same opening-role ring dimension and decomposition basis, so the segments can occupy disjoint column ranges of the single opening-commitment matrix and form one input vector:
Here the concatenation is logical and follows relation order: the final/new group first, then the precommitted groups in public order. It combines only the opening-digit inputs to ; the original group witnesses, folded responses, and outer-commitment digits remain group-local. The fixed column ranges record which coordinates came from each group, and the group-local consistency rows prove what each segment represents at that group's own opening point.
Semantic relations and witness layout
In the canonical semantic-row order, the final/new group is placed first, followed by the precommitted groups. The shared rows follow all group-local rows:
The semantic target vector is therefore
The semantic layout is block sparse: a group's consistency, , and rows touch only that group's witness segment, whereas the shared rows touch the segments from every group. Stage 2 batches the realized physical rows into one sumcheck, but this batching does not merge the group-local relations.
The corresponding logical witness layout is
The displayed rows, target vector, and are the complete semantic multi-group relation under this section's single-chunk, common-ring assumptions. They specify the algebraic variables, row support, and group ordering without choosing a public payload representation.
Raw and compressed modes realize this semantic layout as described on the realizations page. Multi-grouping changes the group-local row blocks and the input layout of the shared relation, but not the ordinary quotient or compression machinery.
Return to the single-group recursion
The root fold consumes this multi-group semantic structure. After the semantic rows have been realized and prepared for field checking, their witness coordinates form one complete flat ring-switch witness. That witness is aligned to the successor commitment ring dimension and committed once. Stage 2 evaluates it at its sumcheck-derived opening point, producing one witness-side opening claim for the next fold.
Thus the contribution descended from the original root batch is one committed witness and one opening claim. Its coordinates retain the original group ranges inside the flat layout, but those root groups no longer define separate folded responses or relation rows. If setup offloading is active, the next fold may also receive an independent setup-prefix group; that extra group does not preserve or recreate the original root grouping.
Multiple witness chunks
Why multiple witness chunks
The basic fold immediately reduces all live blocks to one folded response
This is algebraically compact, but it creates a synchronization point when the source blocks are distributed across GPU workgroups, devices, or machines. Each worker already owns a contiguous block range together with the semantic inner rows retained in the commitment hint. Forming one outgoing would require the workers to reduce their full-width responses before that response could enter the next witness.
A multi-chunk fold retains those local responses instead. A worker can derive its opening digits and folded-response digits from the same local blocks and contribute one unit
to the outgoing witness. The smaller outer- and opening-commitment images can still be combined across chunks. Linearity then lets the relation sum all chunk contributions in the original rows. Thus multi-chunking changes the witness columns, not the semantic row families or their public targets.
The protocol defines chunks as witness block ranges, not as trusted parties or a required execution schedule. An implementation may map a chunk to one GPU workgroup, device, or machine. The current prover also retains the aggregate internally where useful; the protocol-level change is that the committed witness carries the local responses rather than one global response.
This locality has a cost. The and segments are partitioned across chunks and do not grow in total, but every chunk carries a full-width segment. For chunks, the live ordinary witness therefore gains coordinates relative to the single-chunk layout.
| Object | Effect of multi-chunking |
|---|---|
| Replaced by full-width local responses | |
| Partitioned by block range; total width is unchanged | |
| Remain aggregate commitment images | |
| Semantic rows and targets | Remain unchanged |
Chunk ranges and commitment-side data
To isolate the chunk axis, assume one commitment group, one polynomial claim,
the EvaluationTrace opening method, one unsliced matrix, and one
common ring
Commitment slicing is a separate axis. It uses the same proportional partition, as described in B slices and chunks.
Let be the number of live blocks. Let be a supported power-of-two chunk count and, for this derivation, assume . For , chunk owns the equal-sized range
Root source chunks use the canonical proportional partition, including unequal and empty ranges. When the producer has multiple chunks, each emitted Z/E/T body is aligned to a multiple of the next fold's source-block coefficient width. The canonical prover fills the alignment gaps with zero. The next fold inherits those bodies instead of repartitioning the witness equally; if its chunk count contracts, it merges adjacent owners. The last owner also receives the complete quotient and compression tail and the final power-of-two padding. T ranges end before the alignment gaps, which add no semantic Z/E/T coordinates. The gaps belong to the committed witness and obey the ordinary digit range constraints, but carry no relation equations. Verification does not require zero. Zero filling adds no energy to the honest prover's source model; nonzero filler becomes part of the next fold's source and can affect its responses, which must still meet that fold's enforced bounds. See response security accounting. This ownership changes no relation below. The transcript still samples one challenge for every global live block; it does not sample an independent challenge family for each chunk.
Before the opening query, the incoming commitment has already fixed the commitment-side data. For every , the commitment computation viewed the -th polynomial block as one vector and formed its inner image
Here contains all inner-digit ring elements in block ; no additional coordinate indices are needed for this commitment path. Let denote the outer gadget-recomposition map applied coordinatewise to an inner image. Its bounded digit representation satisfies
The commitment hint retains the recomposed inner images , not materialized outer digits. During the current fold, chunk decomposes the images belonging to its range and collects the recovered digits as
The complete outer-digit vector and the corresponding column partition of are
The chunk-local outer image
is an algebraic partial contribution, not a separate payload. The semantic commitment is
Raw mode exposes the aggregate . In compressed mode, the chunk-local images are first reduced to this single ; only then is used as the hidden source of one shared chain. Multi-chunking does not create one compression payload per chunk.
Chunk-local partial evaluations and opening commitment
The opening point supplies the same opening vector as in the basic derivation. Let recompose the inner digits at every position of a block, and let be the row map induced by the weights . For every block , chunk computes the partial evaluation directly from its block vector and decomposes the result:
Here recomposes the opening digits of . Collect the blocks belonging to chunk into . The complete opening-digit vector is their concatenation:
The partial evaluations and the digit segments remain local to their chunks. Partition the columns of the opening-commitment matrix along the same ranges,
Chunk can then compute its opening-commitment contribution directly:
By linearity, the semantic opening commitment is obtained by reducing only these smaller images:
Thus a distributed prover does not aggregate the block-indexed partial evaluations or their digit segments. Each worker first applies its local columns of , and the workers aggregate only the resulting opening-commitment images. Like , the partial image is not a public payload. Raw mode exposes the aggregate . In compressed mode, the workers likewise first reduce their partial images to the single ; only then is used as the hidden source of one shared chain. Multi-chunking does not create one compression chain per chunk.
Chunk-local folded responses and witness relations
The payload binding and is fixed before the transcript samples the fold challenges . Computing the basic global response at this point would require the workers to reduce a full-width vector. Multi-chunking instead keeps the response local.
Chunk then folds only its own source blocks:
Each has the same full ambient width as the single response . It is a partial sum over blocks, not a width slice. Decompose it with the ordinary fold gadget. Writing for its coordinatewise recomposition map gives
Together with the local opening and outer-commitment digits, this gives the chunk-local witness unit
Within the logical witness for the four ordinary semantic relation families, the three segments of each unit are contiguous, and the units themselves are concatenated in chunk order:
Thus is the complete chunk-major logical witness for those four families, not one separately proved witness per chunk. The physical witness aligns multi-chunk bodies with zeros, then appends quotient digits and compression data as required by the selected relation and payload modes. The complete witness layouts describe both choices.
The local responses still define the same global folded response algebraically:
The global is therefore determined by the chunk-local witnesses, but it is not an additional committed coordinate and need not be materialized through a full-width reduction before constructing the outgoing witness. The distributed prover explains how the workers combine partial commitments to that witness.
The basic is not a concatenation or reordering of the local segments. Recovering that digit vector would require materializing the global and decomposing it again; the multi-chunk relation avoids that full-width reduction by acting on the local digit vectors directly.
This aggregation must also be reflected in weak binding. Stage 1 checks every against the same balanced digit interval, but the shared A rows bind . For basis and fold depth , one accepted chunk has exact difference diameter ; accepted chunks therefore have aggregate diameter . The A-role SIS row is sized for this aggregate envelope, not for a single chunk. Honest chunk norms may differ because the block ranges are ragged, but every chunk keeps the same basis, depth, and full ambient Z width.
Because the ranges partition the live blocks, this derived still satisfies the two recomposed identities from the basic setting:
Substituting the digit decompositions of , , and the derived gives the aggregate fold-evaluation consistency relation
The same substitution gives aggregate inner-commitment consistency:
Semantic relations remain unchanged
For the complete chunked witness , the four proved semantic relations can be read together in canonical row-family order:
These are the same four semantic relations as in the basic setting. Their semantic target remains
Each relation sums the relevant chunk-local witness contributions inside the original rows. Multi-chunking does not create a separately proved row family for every chunk; it changes the witness layout and the column support of those rows.
Raw and compressed modes realize these same semantic relations as described on the realizations page. Chunking does not replicate the ordinary quotient family or the shared compression chains. The field-valued evaluation trace likewise remains one virtual relation over the chunk-local opening-digit ranges, not an additional physical ring row; its construction is described in Field-to-ring evaluation reduction.
When , the sole range contains every live block, the single local response is , and every equation and witness layout above reduces to the basic single-chunk construction.
Mixed commitment-ring dimensions
Why use different ring dimensions
The common-ring derivation gives , , and one dimension because that is the simplest setting in which to see the four semantic relations. The three matrices perform different jobs, however, and need not have the same best dimension. The matrix carries the source and folded witness, the matrix binds the outer-commitment digits, and the matrix binds the opening digits. A larger ring may improve fold geometry or shorten the recursive schedule, while smaller or rings may give better commitment ranks, quotient sizes, setup cost, or verifier work.
To isolate this axis, return to one commitment group, one witness chunk, and
the EvaluationTrace opening method, but allow the three commitment matrices
to use
The supported dimensions are powers of two and satisfy
There is no ordering requirement between and . The uniform setting is the projection-ratio-one instance of the same protocol, not a separate relation path.
Mixed rings preserve the meaning of the four semantic relations. They change the native ring in which each physical row is represented:
| Semantic relation family | Native ring |
|---|---|
| fold-evaluation consistency | |
| inner-commitment consistency | |
| outer-commitment consistency | |
| opening-commitment consistency |
Thus the four families do not each receive an arbitrary ring. The two consistency families remain -native, while the two commitment-image families use the native rings of and .
Role-native projection and decomposition
The source block , its inner image , the partial evaluation , and the folded response are first formed over . Before is decomposed for , or is decomposed for , the implementation splits the -native value into exact role-native coefficient subcolumns.
Let be either or , and let . For , define
Taking the canonical representative of degree less than , has the exact decomposition
Here is digit-decomposed inside its native role ring. Equation (6) is a coefficient identity, not an embedding of into and not padding to an -sized carrier. The physical digit order is
[semantic value][role subcolumn][digit][native coefficient].
The representation of an -native value therefore has subcolumns, and its representation has subcolumns. Write and for the corresponding recomposition maps, including the shifts and from Equation (6). They reconstruct -native values from the role-native digits used by the consistency relations.
The four relations in their native rings
The fold still computes
With role-native recomposition made explicit, the four semantic relations are
The first two rows compare values that originate from the -native source, so they recompose the - or -native digits back into . The last two rows operate directly on those role-native digits. The physical columns of and include the subcolumn axis, so neither matrix pads its input back to .
The canonical row-family order and targets remain
This notation records the row order and semantic targets; in the mixed setting it is not one vector equation over a common ring. Each component is interpreted in the native ring shown in Equation (7).
The ordinary witness is stored as one flat coefficient vector. Its segment is -native, its and segments use the role-native subcolumn layout, and every quotient row added by the physical realization is stored at that row's exact native dimension. No batch-wide carrier ring is introduced for witness storage.
Check each row in its native ring
For EvaluationTrace, consistency and rows use ,
rows use , and rows use . Apply the
selected checking method to each row at that row's native dimension .
Quotient lifting uses its modulus factor and private
quotient digits. Reduced evaluation uses its public kernel
without quotient digits.
Both methods evaluate at the shared field point . The resulting scalar claims lie in the same extension field and can be batched with . This does not convert the original relations into one common quotient ring. Checking ring relations over a field derives the two checks and their handoff to Stage 2.
Relation to compressed realization
Compressed realization uses the selected ring-relation mode for its additional native rows as well. In raw mode, the semantic commitment images and are public. In compressed mode they are private intermediate values, and additional and rows bind them to smaller public payloads. Those compression rows have their own native ring dimensions. Quotient lifting gives each one a native quotient; reduced evaluation uses the corresponding residue weights without quotient digits.
The difference is structural. Mixed // dimensions assign native rings to the existing four semantic relation families. Compression adds new / physical row families. Once the rows have been formed, the selected ring-relation mode turns them into field claims before Stage 2.
Choosing a smaller or is not automatically cheaper. The physical column counts expand by the projection ratios
and, for fixed digit depths, splitting a value does not reduce the total number of its or coefficients. The benefit instead comes from the complete interaction among native commitment ranks, payload and quotient sizes, setup geometry, verifier arithmetic, and later fold levels. The planner therefore prices complete schedules rather than minimizing each dimension independently.
Composition with groups and chunks
Mixed dimensions compose with the two earlier axes without changing their ownership rules. Each commitment group owns its and dimensions, while the consuming level owns the shared dimension. Each chunk retains the layouts of its group's unit; chunking changes the block ranges and column support, not the ring assigned to a relation row.
With multiple groups and chunks, the exact unit order is
The resulting physical witness remains one chunk-major flat coefficient vector with any required compression suffix. Quotient-lift mode adds the shared ordinary quotient digits and any compression quotients. Each row uses its own dimension in the quotient-lift weights or the reduced-evaluation kernel. Thus group, chunk, and mixed-ring layouts combine without introducing a common carrier ring.
Opening points and digit-innermost layout
Akita uses one physical source order at the root and at every recursive level. For one commitment group, let
N = exact live source ring elements per claim (num_live_ring_elements_per_claim)
L = num_positions_per_block, positions in one block, a power of two
F = num_live_blocks = ceil(N / L), the exact number of live blocks
The physical source index is
source_index = block_idx * num_positions_per_block + position
so position is the low-order coordinate and block_idx is the high-order coordinate. The final block may be partial; it is not padded in the stored source.
Opening point split
An opening point first contains log2(num_positions_per_block) position coordinates. The remaining
coordinates address next_power_of_two(num_live_blocks) block slots. Akita constructs all L
position weights but retains only the exact live prefix of F block weights.
There is no virtual compact-to-padded address map and no root-versus-recursive
block-order mode.
RingOpeningPoint exposes the resulting factors directly:
position_weights: length num_positions_per_block
live_block_weights: length num_live_blocks
Both the Lagrange and monomial bases use this same physical order.
Witness order
Decomposition digits are innermost. For each group and chunk, the canonical physical unit is
[z_hat | e_hat | t_hat]
The logical orders are
z_hat[position][commit_digit][fold_digit][A_coefficient]
e_hat[claim][block_idx][D_subcolumn][opening_digit][D_coefficient]
t_hat[claim][block_idx][A_row][B_subcolumn][outer_digit][B_coefficient]
r_hat[relation_row][quotient_digit][native_row_coefficient]
The T digit is the outer commitment digit. The active
role-native-projected-digit-layout
spec defines the mixed-dimension cutover. Under that contract, E and T split
each A-ring value into native D or B subrings before decomposition. Their target
coefficient orders are:
e_hat[claim][block_idx][D_subcolumn][opening_digit][D_coefficient]
t_hat[claim][block_idx][A_row][B_subcolumn][outer_digit][B_coefficient]
Only live subcolumns are stored. When every role dimension equals A, the subcolumn axis has length one and the byte order is the uniform layout.
WitnessLayout
is the range authority shared by planning, proving, setup, relation evaluation,
recursive handoff, and verification. Units are ordered by chunk and then
authenticated relation group. Each unit records its exact
global_block_start, num_live_blocks, and coefficient ranges.
In QuotientLift mode, the complete physical order depends on the payload:
raw:
[chunk-major, relation-group-ordered Z | E | T units]
[ordinary consistency, A, B, and D quotient rows]
compressed:
[chunk-major, relation-group-ordered Z | E | T units]
[ordinary consistency, A, B, and D quotient rows]
[alignment to the common relation coefficient block]
for compression layer l = 1, 2:
[alignment to the largest native F_l or H_l ring dimension]
[F_l digit spans, one per group in relation order]
[the shared H_l digit span]
[F_l quotient rows, in the same group order]
[the H_l quotient row]
[suffix alignment to the common relation coefficient block]
In ReducedEvaluation mode, omit every ordinary and F/H quotient row from
these diagrams. The Z/E/T units and any compression digits remain.
WitnessLayout computes the required alignment for the selected mode; it does
not reserve placeholder ranges for omitted quotients. The ring-checking
chapter explains
why the two methods need different witnesses.
In quotient-lift mode, r_hat is logically one quotient family in
relation-row order, but its compression rows are physically interleaved with the corresponding digit
layer rather than stored in one contiguous quotient tail. Every alignment
range is zero. Boolean padding, if needed by a later flat-table sumcheck, is a
separate zero suffix after the complete live witness.
In compressed mode, the negative-binary constraint is active exactly on one
interval per layer, from that layer's first F digit through the end of its
shared H digit. These intervals include the padded F and H digit spans,
but exclude all ordinary and compression quotient rows and all alignment
ranges. Raw mode has no compression layers or such support intervals.
Chunks and fold challenges
Root source chunks own contiguous ranges of the exact F live blocks. For chunk i of
P, the canonical range is
[floor(i * F / P), floor((i + 1) * F / P))
The ranges stay exact and contain no padding. Their lengths differ by at most
one block. If P > F, repeated boundaries give empty ranges while preserving
all P machine slots. An empty slot has no E or T coefficients, but it keeps
the full replicated Z segment and the honest prover fills that segment with
zero. All supported chunk counts are powers of two. Therefore, every finer
chunk partition refines every coarser partition.
After a multi-chunk producer, a recursive witness inherits its chunk-major Z/E/T bodies. Each body ends at a multiple of this fold's source-block coefficient width; the T range itself excludes the alignment gap. The canonical prover zero fills these committed, range-constrained coordinates; verification allows nonzero filler subject to the response bounds. Adjacent owners merge when chunking contracts, and the last owner receives the complete shared tail and final power-of-two padding. These inherited ranges can differ by more than one block. Single-chunk producers keep the original contiguous Z/E/T layout without body alignment padding.
Each commitment group owns a fold challenge with F independent sparse
coefficients, one for every live block.
B slices and chunks
B slicing uses proportional block ranges independently of witness ownership. For
slice i of S, the range is
[floor(i * F / S), floor((i + 1) * F / S))
Unlike chunks, B slices must be nonempty, so S <= F. Both S and the witness
chunk count are powers of two. At the root, one proportional partition refines
the other. For inherited witness chunks, a slice/chunk intersection is the
intersection of their exact contiguous block ranges. The protocol selects S
and the chunk count independently. It does not create a product partition.
Slicing does not change the opening point, block indices, or fold challenge coordinates. It only changes how the existing block-ordered T input is sent through B. Relation B rows are ordered by slice and then by physical B row. Shorter slices keep the same physical column order. Each polynomial-major segment gets its own zero suffix before the next polynomial segment begins.
Validation boundary
Malformed dimensions, overflowing sizes, invalid powers of two, and block or
chunk indices outside the exact live ranges are rejected with AkitaError.
Verifier-reachable code does not recover an obsolete block-order interpretation.
Fold path and field geometry
Akita uses one fold engine for every field tier. The schedule selects the opening method for each nonterminal fold.
| Opening method | Production use | EOR |
|---|---|---|
SubringCoefficientPacking | Required at levels 0 and 1 and every multi-chunk fold; optional at later single-chunk folds | omitted |
EvaluationTrace | Eligible single-chunk folds at level 2 or later and the terminal path | required only when the claim field is a proper extension |
See Coefficients and evaluation points have different roles. For the packing path, read the three obligations in order: the direct scalar opening, the source/fold consistency identity, and the physical quotient and ring switch.
The extension degree fixes the number of field coordinates in one claim. It does not select the opening method. In particular, an fp128 schedule may use coefficient packing even though its extension degree is one. That choice can reduce the D input width even though there is no EOR proof to remove.
Single-field path
When EXT_DEGREE == 1:
prove_rootprepares coefficient packing for every root group.- Recursive folds use packing at level 1 and every multi-chunk fold; later single-chunk folds may dispatch to packing or evaluation trace.
- Shared
prove_foldruns the ring relation, ring switch, and sumchecks. - No EOR payload is produced because the extension degree is one.
The verifier mirrors this path. A scalar root is the one-group case of the grouped root verifier.
Extension claim path
When EXT_DEGREE > 1, the schedule still selects the method. Coefficient
packing opens the original extension valued claim directly and emits no EOR.
Evaluation trace uses EOR to bridge base field coefficients to the extension
valued opening. The verifier accepts an EOR payload if and only if the scheduled
method is evaluation trace and the extension degree is greater than one. See
Extension-opening reduction.
Every group consumed by one fold uses the same method family. Packing groups may use different challenge subring dimensions. A setup prefix inherits the method selected by the fold that consumes it. The commitment itself does not record that method.
For coefficient packing, ring-switch finalization prepares one compact batch
of checked group semantics. The batch retains shared sparse challenges, alpha
powers, row weights, gadgets, and witness addresses. It supplies both the
Stage 2 opening terms and the CPU relation events. The CPU calls
coefficient_packing_relation_events on those groups when it needs expanded
weights; shared preparation does not evaluate the challenges or allocate events.
This keeps both consumers tied to the same fold inputs while allowing other
backends to consume the compact batch directly. The verifier evaluates its
challenges once per group when building compact factors.
Implementation map
crates/akita-prover/src/protocol/prove/fold/.crates/akita-verifier/src/fold/andcrates/akita-verifier/src/stages/.crates/akita-params/src/layout/params/precommitted.rs.crates/akita-params/src/layout/subring_packing_geometry.rs.crates/akita-types/src/subring_coefficient_packing.rs.
Root fold and ring switching
One folding step builds a batched relation and switches it into the next ring witness. The schedule also selects how each commitment group is opened.
Subring coefficient packing
The preceding pages established the two semantic facts needed by
SubringCoefficientPacking:
- the direct packed scalar row recombines the packed opening digits into the original scalar claim; and
- packing commutes with the sparse source fold, so the packed partial and folded source describe the same random combination.
This section starts from those facts and explains their physical realization: the packing quotient, its coordinate planes, and evaluation at the ring-switch challenge.
Native geometry
Let be the base field and the opening field, with . The schedule chooses , , and a packing factor satisfying
The implementation and live specification call these values d_A, s, and
h, respectively. The three relevant rings are
| Ring | Definition | Physical role |
|---|---|---|
| A ring | source witness and A rows | |
| challenge subring | sparse fold challenges | |
| extension opening ring | packed partial and packing quotient |
The embedding used by the A relation is
The two-dimensional source table already showed how the columns are contracted and the rows are kept. This page starts from its output. One packed partial has coefficients in . Expanding each coefficient in the canonical basis gives the following physical representation:
| Object | Logical shape | Base-field storage | Width |
|---|---|---|---|
| all packed partials | one -coefficient element of per claim/block pair | [claim][block][extension coordinate][subring coefficient] | per pair |
| one group's | one degree-below- polynomial in | [extension coordinate][subring coefficient] |
Within either object, one extension-coordinate plane contains all coefficients in increasing order. Its width is not the dimension of one larger ring. A packed partial is one logical -valued element represented by base-field planes. The quotient has the same coefficient shape, but is kept as a degree-below- representative in . The D commitment, or its compressed H realization, binds the digit-decomposed partial planes before the fold challenge is sampled.
The packing consistency quotient
Let be the packed partial for a live claim/block pair and let be its fold challenge. For the folded-source digits, use the shorthand
This notation preserves the vector: the sum recomposes only the fold digit index . Applying the packing map gives . Semantic consistency says
Canonical representatives of the two sides need not be equal as ordinary polynomials. Their difference is divisible by the cyclotomic modulus, so the prover supplies
such that the following identity holds in :
The quotient also has coefficients in , hence coordinate planes of
length . Its digit coordinates occupy the consistency-row slot in the
shared pre-compression quotient range. In Stage 2, the packed E and Q events
join the common relation-weight factorization, while the folded-source side is
the separate packing-Z structured term. These contributions replace the
legacy EvaluationTrace consistency coefficients; they do not add a second
copy of the obligation.
Evaluate the native relations at one challenge
After the quotient and next witness are bound, the transcript samples the ring-switch challenge . Evaluating Equation (1) at gives
The A rows use the same challenge polynomials through the embedding. For a challenge
the two required evaluations are
Equation (3) does not introduce a second transcript challenge. It evaluates one coefficient list in the two native geometries required by packing consistency and the A relation.
One packing fold in transcript order
- The schedule fixes , , the canonical extension basis, and the sparse challenge family.
- The prover forms each packed partial and digit-decomposes its base-field coordinates.
- The prover binds the complete D payload, or its compressed H payload.
- The transcript samples one for each live claim/block pair.
- The prover folds the A-ring sources with and computes .
- The prover binds and the next witness; only then does the transcript sample .
- Stage 2 checks the scalar opening, Equation (2), and the A rows using the two evaluations in Equation (3).
This ordering fixes the packed digits before the subring challenges and fixes the quotient and next witness before the evaluation point.
Worked production geometry
For the fp32 candidate
d_A = 1024,
k = 4,
s = 128,
h = 2,
k h = 8,
the A-ring coefficient index is a + 8j. For every fixed j, the partial
contracts eight base-field coefficients into one element of the degree-four
extension field. That value occupies four base-field coordinates:
evaluation-trace partial: 1024 coordinates in F
packed partial: 128 values in E
128 * 4 = 512 coordinates in F
The packed partial and are each half as wide as their
full-A-ring counterparts. The challenge embeds at exponents
0, 8, 16, ..., 1016.
Choosing s = 64 with the same d_A and k would instead give h = 4 and
256 base-field coordinates per packed object. That smaller subring needs a
different sparse challenge family and can increase the A response bound or
change the recursive suffix. The planner therefore prices the complete
schedule rather than minimizing s alone.
Scope and schedule placement
Packing gives two direct savings at an eligible fold: it removes EOR for a proper extension-field opening, and it reduces each partial and packing quotient from to base-field coordinates before digit decomposition. It does not shrink every proof component by ; gadget depths, matrix ranks, compression payloads, response bounds, and later folds can change.
Current generated schedules require packing at levels 0 and 1 and every
multi-chunk nonterminal fold. Every group in such a fold
must have a feasible packing assignment, and one fold cannot mix packing with
EvaluationTrace. Single-chunk folds at level 2 or later may choose either
method when their source encoding supports it. All roots retain packing over
canonical coefficients. The terminal uses EvaluationTrace; packing adds neither
an EOR payload nor a packing terminal.
This chapter documents the implemented relation and schedule boundary. The active design record gives the planner and algebraic soundness requirements. Indexed coordinates supply fork structure for the accepting-tree extractor; the indexed fold bound charges every adversarially touched or verifier-completed coordinate stream.
The root fold
OpeningClaimsLayout routes polynomial groups to claims. Each group keeps its
own public point, commitment profile, and opening geometry. The relation order
is final group followed by precommitted groups. A recursive fold uses the same
group rules for its folded witness and an incoming setup prefix.
Ring switching
The schedule selects how each fold turns its native-ring relations into field
relations for Stage 2. In QuotientLift mode, the prover supplies a unique
polynomial-modulus quotient for every physical relation row. The derivation
below describes this mode.
ReducedEvaluation instead moves negacyclic reduction into public coefficient
weights and creates no polynomial-modulus quotient rows or quotient digits.
Production schedules admit it only as a monotone, setup-direct
single-chunk EvaluationTrace suffix beginning at any eligible fold. Coefficient packing
remains quotient-lift-only. Checking ring relations over a
field derives both methods and their schedule
restrictions. This section explains how the prover computes the quotients.
This operation is distinct from EOR. EOR changes an extension-valued opening
claim before the lattice relation is formed. In QuotientLift mode, ring
switching lifts the resulting lattice relation out of its quotient ring so
that sumcheck can prove it over a field.
Recover the quotient from two convolutions
Let a(X) and s(X) have degree less than D, and write their ordinary
product as
where both L and H have degree less than D. Reducing this product modulo
the cyclic and negacyclic moduli gives
The field has odd characteristic, so division by two is defined. The high half of the ordinary convolution is therefore
Equation (4) is exactly the quotient in
For a complete row of the relation, let
The quotient-ring equation says that [P_i]_(X^D+1) = h_i. Consequently, the
ordinary-polynomial identity used by Stage 2 is
with
The prover digit-decomposes each r_i and appends those digits to the recursive
witness. After the verifier substitutes X = alpha, the factor X^D + 1
becomes the public scalar alpha^D + 1. This turns every lifted row into a
field relation suitable for the fused Stage-2 sumcheck.
Preserve each row's native ring
Akita does not enlarge every relation to one common ring dimension before
computing Equation (5). Consistency and A rows use d_A, B rows use d_B, and
D rows use d_D. Their quotients retain those same native dimensions. This is
both the mathematical layout and the physical recursive-witness layout; the
row geometry records the native dimension and the number of coordinate planes.
The coefficient-packing consistency row is the one nonstandard geometry. It is
an equation over E[Y]/(Y^s + 1), represented as k base-field coordinate
planes of length s. Its quotient therefore has k s physical coordinates.
It is not reinterpreted as one ring of dimension k s. Its modulus evaluates
to alpha^s + 1, as in the packing identity in Equation (2).
Compute only the coefficients that survive
The matrix rows use paired cyclic and negacyclic transforms to obtain Equation
(5). Akita performs both convolutions through the same CRT profiles used for
ring multiplication, then converts their difference back to the base field and
multiplies by 1/2.
Sparse challenge products need less work. If a nonzero challenge coefficient
is at position p, only source coefficients D-p through D-1 can reach the
high half of the ordinary convolution. The quotient kernel visits only those
coefficients and accumulates directly into r; it does not form the low half
that negacyclic reduction would discard. The same rule applies when the
consistency row combines folded opening material with sparse challenges.
Compressed commitments introduce additional F and H relation rows. Their quotients use the same cyclic-versus-negacyclic identity and remain attached to the compression layer that owns them. Compression changes the row layout, not the algebra of Equation (5).
Cached and streamed execution are equivalent
The CPU backend chooses between two execution plans after the complete row geometry has been validated:
- A retained operation reuses the exact transformed setup prefix held by the prepared setup.
- A large operation transforms CRT-safe chunks of the same logical prefix as it proceeds and releases each chunk afterward.
Both plans cover the same rows, columns, transform domains, and quotient coordinates. The CRT capacity bound limits how many products may be accumulated before reconstruction in either plan. This choice affects time and memory only; it does not change setup identity, proof bytes, transcript order, or the quotient checked by the verifier.
Implementation map
crates/akita-prover/src/protocol/ring_relation.rsassembles ordinary relation terms.crates/akita-cpu-backend/src/opaque/witness_build/relation_quotient.rscomputes the role-native ordinary quotients and sparse high-half contributions.crates/akita-cpu-backend/src/arithmetic/ring_switch.rsselects the retained or streamed CPU kernels.crates/akita-prover/src/protocol/ring_switch.rsassembles the ring-switch witness and proof state.crates/akita-cpu-backend/src/opaque/witness_build/coefficient_packing.rsforms packed partials and the packing quotient.crates/akita-cpu-backend/src/arithmetic/coefficient_packing_fold.rsholds the packing map, the direct partial and scalar-opening formulas, and the subring-challenge fold products.crates/akita-params/src/layout/subring_packing_geometry.rsdefines and validates the packing geometry.crates/akita-types/src/proof/coefficient_packing_relation.rsvalidates the packing groups and exposes their checked Stage 2 semantics. The CPU backend expands those semantics into local Stage 2 term tables.crates/akita-verifier/src/coefficient_packing_relation/builds the verifier's compact factors from the same validated groups.crates/akita-verifier/src/fold/replays the relation and rejects a proof whose dimensions or quotient structure do not match the selected schedule.
Sumcheck stages
Every non-terminal Akita fold runs a short sumcheck cascade over the fold witness:
- Stage 1 — digit range check. Proves that every witness entry is a valid
balanced digit and outputs one evaluation of the virtual range-image table.
A fold on the
L2route also proves the complete physical response norm in the final Stage 1 substage. - Stage 2 — fused relation sumcheck. Proves the ring-switched fold relation and binds both Stage 1's virtual range-image value and the opening claim carried into the fold to the committed witness; the resulting witness evaluation becomes the next opening claim.
- Stage 3 — setup product sumcheck. When recursive setup contribution is selected, proves the deferred A/B/D setup contribution and leaves one setup-prefix opening claim for the next fold.
This chapter explains the Stage 1 range protocol and the Stage 2 fused relation protocol in detail. Stage 3 is summarized at the end. The terminal fold runs none of these sumchecks. When it uses an L2 route, the verifier computes the clear response norm directly. See The proving protocol.
Contents
- Stage 1: digit range check
- The complete Stage-1 protocol
- Stage 2: fused relation sumcheck
- Stage 3: recursive setup contribution
Stage 1: digit range check
What it certifies
Let
be the balanced-digit table of the newly committed witness. The level chooses one basis
and every Boolean entry must lie in
This range bound keeps the recursive witness norm under control.
The simplest sound design
The direct vanishing polynomial for the balanced alphabet is
A Boolean entry is valid exactly when . Checking only the unweighted sum of these values would not be sound, because nonzero violations could cancel. Instead, the protocol anchors the table at a random equality point and proves
The right-hand side is a random evaluation of the multilinear extension of the Boolean violation table. An equality-factored sumcheck proves this identity one variable at a time; see Equality-factored sum-check.
This design is simple, but has degree . Akita represents the same condition with a degree- polynomial before deciding whether a product tree is needed.
Reduce the degree with the range image
Pair the positive digit with the negative digit :
Define the pointwise range image
and roots
The direct polynomial factors as
where
Thus exactly when . Stage 1 starts from the anchored zero claim
The table is virtual: it is not committed and is not appended to the recursive witness. Stage 1 proves the range identity for ; Stage 2 later proves that its final evaluation comes from on the committed witness.
The complete Stage-1 protocol
Quartic leaves and product substages
For basis or , has degree at most four and one equality-factored sumcheck proves the anchored identity directly.
For larger bases, the protocol partitions the roots into consecutive groups of at most four:
Their product is . Each is quartic except at basis , where
the only leaf is quadratic. Product substages prove how these leaves combine,
using only arity- or arity- products. The topology is fixed by
DigitRangePlan:
| Basis | Product substages | Final leaf |
|---|---|---|
| 4 | none | one quadratic leaf |
| 8 | none | one quartic leaf |
| 16 | arity 2, emitting 2 child claims | batch of 2 quartic leaves |
| 32 | arity 4, emitting 4 child claims | batch of 4 quartic leaves |
| 64 | arity 2, emitting 2 claims; then arity 4, emitting 8 claims | batch of 8 quartic leaves |
One product substage
Suppose the current substage has parent tables , and each parent is the pointwise product of child tables:
Let be the current equality point and the current parent weights. The carried claim is
The product substage proves
At the sumcheck's sampled point , the prover supplies the child evaluations
in canonical order. The verifier closes the substage against
The protocol then:
- absorbs the child evaluations in canonical order;
- samples a fresh interstage challenge ;
- assigns weights in that same order;
- batches the child evaluations into the next carried claim; and
- uses as the equality point for the next substage.
Let the canonical order of the child nodes be , and write their evaluations at as . The child node in position receives weight , so both parties derive the next claim from the absorbed child claims and the transcript challenge:
For the next substage, these canonically ordered child nodes become the new parent nodes. Set its equality point to and its parent weights to . The carried claim is therefore
Equation (2) has the same form as Equation (1), the carried claim proved by each product substage. In other words, the handoff substitutes , , and in the product-substage claim above.
At the root there is one parent with weight and claim . Each product
substage expands the current parents into their children; the fresh powers of
compress those child claims back into one claim for the next
substage. The prover and verifier follow the same transcript order
(digit_range/mod.rs,
stage1.rs).
The final leaf
After all product substages, let be the current equality point, the current batched claim, and the current leaf weights. Define
The final equality-factored sumcheck proves
For bases , , , and , is quartic. For basis , it is quadratic. When there is no product substage, , , and .
At the final sampled point , the proof carries
The verifier closes the leaf against
The distinction between the Boolean table and its MLE matters:
in general. The equality holds at Boolean vertices, but
multilinear extension does not commute with the quadratic map away from those
vertices. The proof therefore carries the independent
range_image_evaluation field
(levels.rs).
Optional physical norm term
An L2 selected fold proves the squared norm of the complete physical folded
response. The physical response domain contains every live Z coefficient once
and assigns zero to padding addresses. WitnessLayout defines this domain for
the prover, verifier, and proof size code.
For a large field, the final Stage 1 substage batches the range leaf with
The proof carries the public integer value , one additional coefficient in each final sumcheck round, and the final virtual evaluation of . The verifier checks against the cap stored in the schedule.
For a small field, the allowed digit range may make the full square sum wrap the base field. The schedule then divides the physical domain into fixed blocks and proves bounded limb inner products. Each subclaim has a unique centered integer lift because its public bound is below half the modulus. The verifier reconstructs with checked integer arithmetic and rejects a wrong subclaim count, an overflow, or a value above the cap.
The proof stream has no route header. The schedule determines whether the norm
proof exists and gives its exact shape. An L∞ fold uses the ordinary Stage 1
shape and carries no norm values.
Domain and challenge order
Stage 1 views the digits as one flat Boolean table. The live witness occupies a prefix; every remaining address is public zero padding. Zero is a valid balanced digit, so padded entries also satisfy the range polynomial.
Ring switching supplies in column-then-ring order, while the flat
table binds variables in increasing physical-address-bit order. The protocol
reorders the point so that ring-slot coordinates come first, followed by
column coordinates
(stage1.rs).
The verifier
The verifier replays the same product substages, derives the same interstage
challenges and weights, checks each child-product claim, and closes the final
leaf at range_image_evaluation
(stage1.rs).
Passing Stage 1 proves that the range-tree claims are internally consistent and
reduces the final leaf to range_image_evaluation. It does not by itself
tie that virtual value to the committed witness.
Stage 2: fused relation sumcheck
Stage 2 always proves three statements about the same committed digit witness :
- satisfies the ring-switched fold relation;
- Stage 1's virtual range-image value is correctly derived from ; and
- the opening claim for this fold is consistent with .
The protocol fuses all three statements into one sumcheck. The range-image and opening-consistency terms are shared by both payload modes and both ring-relation modes. Raw payload uses only the ordinary physical rows; compressed payload adds compact relation weights and a support-restricted constraint for the compression digits. Separately, quotient lifting uses a factored relation weight over explicit quotient digits, whereas reduced evaluation uses a dense prover weight table over a witness with no quotient ranges. Neither axis adds a second Stage-2 sumcheck.
When Stage 1 also proves a physical norm, Stage 2 adds the Z virtualization relation derived from the schedule. It proves that each final physical response or limb evaluation is the balanced basis recomposition of the committed Z digit plane evaluations at the same point.
Write for everything in the Stage-2 residual that does not depend on the physical-L2 batching challenge, and write for the residual of virtual evaluation . The prover and verifier derive
Thus the constant coefficient belongs only to . The virtual coefficients start at , not at one. This distinction is load-bearing: a coefficient vector would place and in the same constant coefficient, so the prover could arrange the challenge-independent cancellation . With the shifted identity above, an identically zero polynomial has separately zero constant and virtual coefficients.
The transcript absorbs all Stage-1 claims and physical-L2 virtual evaluations before sampling . Direct mode has one virtual residual; LimbGram mode has one per limb. The resulting polynomial has degree at most , and the transcript-grinding plan prices that degree.
Start with the schedule-selected ring relation
Raw and compressed payload realizations defines the physical rows. Checking ring relations over a field derives the two ways to turn them into field claims. Here we first derive the quotient-lift factorization, then state the reduced-evaluation replacement.
Let be the -th ring element encoded by the digit witness, and let row of the ordinary extended fold relation be
In quotient-lift mode, the extended relation includes the quotient witness, so Equation (3) is an equality rather than a congruence modulo a ring polynomial. The public right side is zero for some rows and contains the public data for the remaining rows.
Ring switching samples one field element and evaluates every ring polynomial at that point:
The scalar removes the ring-coefficient dimension from the algebraic relation. It is not a Boolean sumcheck point.
Batch the matrix rows
Suppose the ordinary relation has rows indexed by . Its method-independent
rows are , , and , with their quotient terms.
For EvaluationTrace, it also includes the legacy fold-consistency row and its
quotient. SubringCoefficientPacking keeps the consistency-row slot and its
batching weight, but replaces the legacy coefficients: its packed E/Q
coordinate-plane events join the common relation events, and its
folded-source contribution is added later as the packing-Z structured term.
The protocol samples a Boolean MLE point of sufficient width for the
complete physical row domain and defines
It takes the random linear combination of Equation (4) over all rows. Define
The batched relation is the single scalar claim
This is where the matrix-row dimension goes. It is contracted by before Stage 2 starts its witness-address sumcheck. Consequently, the Stage-2 sumcheck point has no matrix-row coordinate.
Stage 2 proves the relation for this batched row. Soundness comes from the fact that was sampled after the witness was committed: a false collection of rows cannot generally arrange for its random multilinear combination to vanish.
Expand the ring elements into one flat witness
For the moment, suppose every witness ring element has coefficients:
Evaluating at gives
Substituting this into Equation (5) yields
Now view as one flat Boolean address . The low bits select the coefficient and the remaining bits select the witness lane . Define
The native matrix relation weight factors as
so Equation (6) becomes
The Boolean domain is padded with zeros when the live witness length is not a power of two.
The production protocol also permits different ring dimensions in different parts of the native relation. It chooses the largest power-of-two coefficient block common to every role and to the outgoing witness. The low address still selects a coefficient inside that common block. Any remaining high power of , together with the matrix entry and its row weight, is absorbed into the lane weight . Thus the exact factorization continues to hold without adding another sumcheck dimension. The packed E/Q events also preserve this common-alpha factorization and are included in . The packing-Z and direct-opening contributions are ordered structured linear terms that are not forced into it.
Reduced evaluation starts from the same physical rows but replaces each unreduced product coefficient by the public signed-wrap kernel . After row batching and flattening, define to be the complete coefficient multiplying witness entry . It satisfies the same scalar claim
but it does not generally factor as one coefficient-power table times one lane table. The prover therefore materializes and folds as one ephemeral dense Stage-2 oracle. The verifier evaluates its final MLE from terminal residue kernels and the fused setup scan without materializing this table.
For the rest of this chapter, let
Raw and compressed relation terms
Raw mode has no payload-compression term . The mode-selected is its complete relation component, and its and right-hand sides contain the transmitted semantic commitments. The scheduled opening method still contributes below.
Compressed mode retains the method-selected ordinary relation and, in quotient-lift mode, its quotients, but sets the and right-hand sides to zero. Their rows now also contain the source-recomposition terms, and the physical row domain additionally contains the , , , and rows. Thus remains one component of the compressed relation, but it is not a complete relation identity by itself.
To derive the missing component directly, process each compressed physical row in its native ring using the selected relation realization. Define to be the coefficient multiplying the flat witness entry in the -weighted sum of all linear terms not already in .
In quotient-lift mode, the intuition is simpler than the expanded formula. Its first line is only the increment to the existing rows: and their ordinary quotient terms are already in , so adds the missing negative recomposition term. The second and third lines are the two newly added physical rows: links the two compression layers, while binds the last layer to the terminal payload . Their quotient terms lift those native-ring congruences to exact identities. Suppressing component indices, the quotient-lift contribution of one chain is
Here is the set of ordinary rows, is the row weight of , and is the quotient ring element that lifts that compression row. The chain contributes the analogous terms with replaced by . Summing these coefficient weights over every chain and the shared chain gives the single compact Boolean table .
Reduced-evaluation mode has the same row ownership and batching, but replaces each parenthesized lifted identity by its terminal-residue kernel. It has no or witness spans. The verifier evaluates the residue kernels from their separately owned canonical compression-relation program; they are not columns of the fused public setup tensor. Define the complete compressed right-hand side in either mode by
The nonzero new targets in are carried by the terminal and rows. Adding the directly collected compression weights to gives the full compressed relation identity
This follows the same lift-evaluate-batch-flatten procedure as the raw relation, but the resulting compact table does not need to share the factorization because its rows use different native dimensions.
The compression digit spans must also use the stricter alphabet . Let be exactly the union of those digit intervals and define the Boolean table
With a separate batching challenge , compressed mode adds the zero claim
This restriction does not apply to compression quotient digits or alignment padding. At a non-Boolean sumcheck point, the verifier evaluates the MLE of the single restricted table ; it does not multiply separately extended support and equality tables.
Add the range-image binding
Let be the final point produced by Stage 1, and let be the
range_image_evaluation carried by its proof. Stage 1 established a claim
about a virtual table. Stage 2 must connect that table to the committed
witness by proving
This is a sum over Boolean addresses. It does not claim that , which is generally false.
After absorbing , the transcript samples a fresh scalar . The protocol uses to batch Equation (8) with the relation claim.
Add the opening claim consistency
Stage 2 also verifies the incoming opening claim against
the committed witness . The schedule selects how the public opening weight
is prepared. EvaluationTrace uses the trace weights
derived in Field-to-ring evaluation reduction.
SubringCoefficientPacking uses the direct coefficient-packing weights
derived in Field-to-ring evaluation
reduction.
Both methods establish the same linear evaluation-consistency shape
Here we focus only on how this relation is fused into Stage 2. Equation (9) has the same linear form in as a row of the ring-switched relation, so the protocol treats it as a virtual row placed immediately after the physical relation rows. If is that row's index in the padded row domain, the shared row challenge assigns it the weight
The virtual row is not inserted into the physical matrix or its relation-weight factorization. Only its batching weight comes from the row domain. Stage 2 directly fuses
into the sumcheck over the flat witness address . In this way, the opening claim reuses the same row randomness as the ring-switched relation without becoming a physical matrix row.
The implementation does not materialize a dense
table. Define the method-dependent weight
as follows. For EvaluationTrace, it is the compact
trace opening weight ; its legacy
fold-consistency row is already in . For
SubringCoefficientPacking, which production schedules pair only with
quotient lifting, contains the packed E/Q
relation events in place of the legacy consistency coefficients. Its
is the ordered sum of only the packing-Z and
direct-opening terms. Each contribution is therefore included exactly once.
Stage 2 folds each structured linear term under the same challenges and sums
their final values. This preserves the native relation fast path without
building one dense weight table. The
physical packing
realization
explains the quotient and the two evaluations of the shared challenge.
The fused Stage-2 claim
In raw mode, combining Equations (7), (8), and (9) gives the input claim
Stage 2 proves
In compressed mode, the stricter binary claim in Equation (7c) has target zero, while Equation (7b) supplies the complete compressed relation claim. Therefore
and the sumcheck polynomial gains two terms:
Every term uses the same flat witness address . This is why each payload mode still needs only one Stage-2 sumcheck.
Sumcheck rounds and the final point
Let denote the mode-selected polynomial expression inside the brackets in Equation (10) or Equation (10c). In round , after challenges have been sampled, the prover sends
The verifier checks
samples the next coordinate , and sets
After all rounds, these coordinates form the flat witness point
Split it according to the flat address as
In raw mode, the verifier closes the sumcheck against
In compressed mode, the ordinary factors are evaluated for the compressed layout, and the verifier closes the sumcheck against
The value becomes the next-witness opening claim in both modes. The shared range term and the restricted compression-binary term have degree at most three in each sumcheck variable. The ordinary, compression, and method-dependent structured terms have degree at most two. Therefore Stage 2 keeps the same degree-three bound in both modes.
The random objects have separate jobs:
| Object | Shape | What it removes or binds |
|---|---|---|
| one field element | evaluates the ring-polynomial variable | |
| a point over matrix rows | batches all relation rows into one virtual row | |
| one field element | batches range-image consistency with the linear claims | |
| one field element in compressed mode | batches the zero-valued constraint | |
| Stage-1 output point over flat witness addresses | identifies the carried range-image evaluation | |
| Stage-2 output point over flat witness addresses | reduces the complete fused claim to one witness evaluation |
In particular, , , and are not coordinates of one larger point. They contract three different domains.
Stage 3: recursive setup contribution
Stage 3 is controlled by the setup-contribution mode, not by the raw or compressed payload equation above. Payload mode determines whether Stage 2 has the extra and terms. Setup mode determines whether the verifier scans the public A/B/D setup directly or defers that contribution to Stage 3. Current schedules permit recursive setup offloading only inside the compressed prefix, but the Stage-3 algebra remains an A/B/D setup product and does not include the maps. Reduced evaluation is admitted only with direct setup contribution, so any fold that reaches Stage 3 necessarily uses quotient lifting. Schedule validation rejects a reduced fold with an incoming setup prefix or deferred Stage 3 before transcript replay.
After Stage 2 fixes its final relation-address point, let be coefficient of shared setup ring , and let collect all A/B/D row, witness-address, gadget, and mixed-dimension projection weights for that setup ring. The deferred claim used by Stage 2 is
Pad the setup-index domain to a power of two and set outside the active A/B/D footprint. If , , and are the MLEs of the setup table, the setup-index weight, and , Stage 3 runs a degree-two sumcheck on
The implementation binds coefficient variables first and setup-index variables second. At its final point , the verifier checks
This is a setup-only sumcheck. It does not batch Stage 2's next-witness opening. When the next level selects an authenticated setup prefix, it leaves the independent setup-prefix opening
The next fold then receives that opening as one precommitted polynomial group and receives the Stage-2 next-witness opening as a second group at . Its grouped opening protocol later authenticates both claims against their own commitments. Under direct setup contribution, Stage 3 is absent and the verifier computes by scanning the required public setup prefix. See Setup contribution and Stage 3 for the mixed-dimension plan and setup-prefix checks.
Extension-opening reduction
Akita uses extension-opening reduction, or EOR, to reduce a base-field
evaluation claim at an extension-field point to a product claim on a packed
polynomial with fewer variables. A fold uses this path only
when its scheduled opening method is EvaluationTrace and
CommitmentConfig::EXT_DEGREE > 1. Single-field presets never run EOR.
Subring coefficient packing also skips EOR because it opens the extension
valued claim directly. See
Fold path and field geometry. For the two-dimensional
example, row identity, and prover/verifier message flow, start with
Foundations → Extension-opening reduction.
This page describes Akita's scheduling and multi-group execution.
The current prover materializes one dense packed witness table for each claim and one transparent factor table for each group. Claims in the same group reuse that factor. A group with fewer variables is extended to the common sumcheck domain virtually, without repeating either table.
Multi-group openings
A multi-group evaluation trace fold emits one EOR proof and runs one degree-two sumcheck. A coefficient packing fold emits neither. For every evaluation-trace group and claim , the reduction uses the group's complete public point, native packed witness, and transparent factor:
Here is the packed table called on the foundations page. is its group's public coordinate factor. The tilde denotes multilinear extension of a Boolean table.
The public points are independent; equal, nested, and unrelated values use the same per-group preparation path. The reduction embeds all claims in one maximum-arity Boolean domain. After the partials and their input claims are fixed, the transcript samples an early coefficient vector. The prover linearly combines the claim polynomials with those coefficients and sends one degree-two polynomial per round. If a group has fewer variables, Akita treats its witness as independent of the additional high variables and multiplies it by equality to a fixed zero point on those variables. That equality factor has Boolean sum one. The prover stores this cylindrical extension as folding state; it does not allocate repeated witness evaluations. After sumcheck, the prover and verifier truncate the internal challenge vector to each group's native tail before preparing that group's resulting relation point. This internal shared reduction challenge is not an ambient public opening point.
Let be group 's tail length, the maximum tail length, and the first coordinates of the shared sumcheck point . The proof carries one terminal product for every opening:
The extra factors come from equality to zero on the additional variables. An empty product is one. Each excludes its early claim-batching coefficient, but includes . The sumcheck terminal value must equal the early random combination of these products. The transcript absorbs these terminal claims before the prover builds the opening payload.
The application uses a second, independent coefficient vector. It samples these coefficients only after the complete opening payload is absorbed. Stage 2 checks the resulting combination of the terminal claims against the committed witness relation. The early combination binds the logical EOR input claims to the terminal vector. The later combination binds that vector to the committed witness.
Akita keeps the products rather than dividing by . If the later application coefficients are , the trace target and weights express the remaining relation
The verifier computes every and multiplies it into that group's evaluation-trace coefficients. A singleton claim uses coefficient one and needs no claim-batching draw. On the terminal path, Akita checks the single-group trace relation directly against the terminal response instead of running Stage 2.
What the prover stores
For a group g, let W_(g,i) be the packed extension-field witness table for
claim i, and let A_(eta,g) be the transparent tensor factor derived from the
group's public point and the reduction challenge eta. The group contributes
to the batched EOR claim. The coefficients lambda_(g,i) are sampled after the
input claims and partials have been absorbed.
The implementation stores:
- one dense
W_(g,i)table for every claim; - one dense
A_(eta,g)table shared by all claims in groupg; and - one scalar coefficient
lambda_(g,i)per claim.
The packed witness tables are already smaller than the original base-field
tables: the first log2([E:F]) Boolean variables have been transposed into one
extension-field value. The implementation does not allocate another factor
table for every claim.
Put unequal groups in one sumcheck
Suppose the largest group leaves m Boolean variables after packing, while a
smaller group leaves only m-t. Akita views the smaller witness as constant in
the additional t high variables and pins those variables to zero in the
transparent factor. Its virtual contribution is
The Boolean sum of the added equality factor is one, so this extension preserves
the group's claim. The prover retains the native witness and factor tables and
tracks only the accumulated value of the extra equality factor as the new
challenges arrive. It does not expand a table of length 2^(m-t) into one of
length 2^m.
After the shared sumcheck finishes, each group uses only the prefix of the challenge vector belonging to its native tail. The remaining challenges account for its virtual zero-pinned variables.
Fuse folding with the next round
In one ordinary round, each term needs the constant and quadratic coefficients of
times the analogous affine interpolation of A_(eta,g). After the challenge
r is sampled, both tables must be folded at r before the next round.
For a group with at least four live entries, the CPU path combines these jobs. It folds the shared factor and the first witness together, while also computing the first claim's next-round coefficients. It then folds each remaining witness against the already-folded factor and computes that claim's next-round coefficients. Thus the group factor is folded once per round, not once per claim, and the next scan is avoided.
Some field profiles can accumulate a bounded sum of wide products before
reduction. The prover uses that path only when the field's SUM_IS_EXACT
contract proves that the delayed sum is identical to reducing each product.
Other profiles reduce every product immediately. Both paths produce identical
proof coefficients.
Implementation map
crates/akita-cpu-backend/src/opaque/recursive/opening/.crates/akita-prover/src/protocol/prove/opening_reduction.rs.crates/akita-cpu-backend/src/opaque/recursive/opening/dense.rscontains the fused fold-and-accumulate kernels.crates/akita-verifier/src/stages/opening_claims/extension_claim.rs.crates/akita-cpu-backend/src/arithmetic/extension_opening_reduction.rsbuilds the prover's tensor partials and factor tables.crates/akita-types/src/extension_opening_reduction.rsholds the tensor algebra the prover and verifier share.- Historical records under
specs/archive/2026-Q3/document the removed root EOR implementations and the surviving suffix machinery's origin.
The distributed prover
This chapter describes a distributed variant of the Akita prover: how the witness is split across many machines, which parts of one folding step are local, and the single protocol change — keeping a per-machine folded response — that lets the machines avoid shuffling large witnesses between each other. The machines can be separate GPUs, accelerators, or nodes; nothing below is specific to GPUs.
What "distributed-prover friendly" means
We hold the design to three concrete criteria:
- Distributable witness. The witness can be split across independent machines so that each machine owns and processes only its share.
- Low cross-machine communication. Machines must not exchange large payloads. Only short commitment vectors and small round-polynomial messages may cross the interconnect; the large per-machine witnesses stay put.
- Net speed-up. The resulting scheme must stay efficient enough that the per-machine work plus the small aggregation actually realises the parallel speed-up the hardware promises.
Throughout, assume machines (take , so machines). We divide the witness into contiguous block ranges. When the number of live blocks is not divisible by , a machine owns either the floor or the ceiling of the average; when there are fewer blocks than machines, some ranges are empty.
Setup: partitioning the witness
We spell the design out in the single-opening case (one opening point , one commitment, one committed slot). Let be the exact number of live source ring elements, choose positions per block, and set . The block-index Boolean domain has size , but only the prefix is live. Reshape the coefficient table into blocks , padding only the final block when . The opening point induces the inner evaluation vector and the live block vector , and the evaluation is .
We partition the block index set into contiguous ranges
, where
, and assign to machine
. For and , these ranges are
. This is the
canonical proportional partition
owned by WitnessLayout. Larger index spaces are always partitioned at the block
level: for any the block partition induces
.
The public key is still the three uniformly random matrices , , and with . All three are prefix views of one seed-expanded matrix, so every machine regenerates the same public columns locally — no setup is broadcast. In the distributed setting we view them column-blocked, and , where hold exactly the columns indexed by 's blocks, and we restrict the block vector as .
Component-by-component locality
We now walk each component of one folding step and check it against the three criteria.
The outer commitment
Machine stores its blocks and performs the ordinary inner commit on each, restricted to its block set. For every it digit-decomposes the block witness , computes the inner commitment , and digitises it to . Writing for the inner-commitment digits it owns, uses only its column block to form the partial outer commitment
The raw relation image is then the sum . The large local witnesses never leave ; only the short -vectors are summed. The aggregation machine negative-binary decomposes that sum through the two F maps and publishes only the 128-byte payload (criteria 1 and 2).
The opening commitment and the claim
The opening side is computed the same way. For every , computes the local block evaluation , digitises it to , and — using only its column block — forms the partial opening commitment , with . The global opening relation image is . The aggregation machine compresses that sum through the two H maps and publishes only the 128-byte payload . Each machine also forms its partial claim , and the claimed evaluation is .
So the raw , raw , and all follow the same pattern: each machine does the same inner/outer/opening computation as the single-machine prover, but only on its own blocks. The machines aggregate only the small relation images and scalar claims; one aggregation machine derives the shared compression digits and public terminal payloads.
The folded response — the hard part
After the verifier samples the folding challenges, the single-machine prover would form one global folded response
But each machine only holds the blocks in , so it can only compute a partial fold from its partial challenges . Crucially, each lives in the full ambient dimension — the same size as the entire folded witness. Summing the into one global would require an all-reduce of this large folded-witness payload across every machine, which directly violates criterion 2.
The protocol change. Instead of reconciling the , we keep them separate. Each becomes its own piece of the next-level witness: machine carries forward its own and never exchanges it. In effect, the next recursive witness now contains folded responses instead of one, and the machines need no -interaction at all.
Security accounting for the shared response
The aggregate commitment-consistency rows act on . This preserves the algebraic identity of the ordinary fold, but it changes the weak-binding envelope. The digit range check is applied separately to every using one common basis and one common digit depth . Thus a large positive coefficient in one chunk cannot be hidden by a negative coefficient in another. If the digit basis is , the exact difference interval for one chunk has diameter , while the difference interval for has diameter
where is the response-chunk count. With denoting the physical mass of the folding challenge, the A-role collision target is
The planner, generated schedule, and verifier admission all derive this exact raw target and select an audited A-role cell no smaller than it. A matrix sized for one response cannot be reused for several response chunks. The current SIS table does not add a separate coverage axis for the chunk count, so a two- or four-chunk schedule may use a conservative next-higher cell rather than the tightest possible collision-bound search. Every chunk retains the same full-width buffer—even an empty block range contributes a full-width zero response—whereas the local and ranges follow the actual number of blocks. The number of response chunks is therefore a protocol parameter, not merely a deployment choice. Production schedules expose only a small fixed set of counts, and verifier validation caps the count so that a malicious schedule cannot force arbitrarily fragmented setup evaluation.
Why only the first few rounds keep per-machine
Keeping a separate per machine is not free, so we do it only for a constant number of leading rounds. Two reasons:
- Proof size and fold depth. The separate enlarge the next witness relative to a single . Carrying that growth into the tail and final rounds would inflate the proof size and the number of fold levels, so those rounds keep the single-response protocol.
- Where the cost actually is. Only the first few rounds are large enough to be worth distributing. Once the scheduled recursive folds have reduced the full witness, the remaining rounds are cheap and run fine on a single machine. This does not require the root fold itself to shrink the witness.
So the schedule fixes a constant number of distributed rounds. Those leading rounds retain one per machine; the later rounds return to the single-response Akita protocol on one machine.
The next-round witness and the relation change
After the distributed rounds, each machine holds its own and can proceed to the next round on its own. Supporting this requires changing the witness format and the relation matrix so the relation is stated over the concatenation of the per-machine witnesses rather than over one global folded response. The rest of this chapter makes that change precise.
The per-machine partial root relation
Each machine holds its partial witness and the matching partial commitments, plus the fold of its own blocks. Over , machine satisfies:
Stacking these, has a local partial root relation
Denote the block matrix by , the local witness by , and the right-hand side by , so the local relation is compactly .
The virtually shared root relation
The verifier never sees the local ; it sees only the public output , whose entries are the sums of the partial values, and . So instead of exposing the local right-hand sides, the machines jointly prove one virtually shared root relation. With and the horizontal concatenation ,
The relation is virtually shared because no machine materialises the full witness or the full matrix : holds only and its column blocks , while the verifier checks the single public right-hand side obtained by summing the partial commitments.
Ring-switch lift and next-level commitment
Each machine lifts its partial relation from to : there is a unique quotient , with , such that
Summing the local identities, the global quotient is the coefficient-wise modular sum , just as the global commitments are sums of the partial commitments. The aggregated quotient is digit-decomposed as , recovering the same ring-switch witness shape as the single-machine protocol — except the root witness stays written as the concatenation of the per-machine witnesses.
Let be the extended witness. The lifted relation is over , with
The extended witness is assembled into the coefficient table of the next-level multilinear polynomial: each machine contributes its segment , and a pre-assigned aggregation machine additionally contributes the quotient segment . The machines then run the ordinary inner/outer commit at the next level's parameters on their assigned portions and sum the partial next-level relation images into one . The aggregation machine compresses and retains the two shared F digit vectors. The verifier sees exactly the single-machine recursive interface: one 128-byte extended-witness payload and one next-level opening claim.
Ring-switch and row-batching
For the verifier samples the ring-switching challenge and the row-batching point . Viewing the machines as one virtual prover, both sides evaluate the extended matrix at , obtaining and the target , i.e. row equations. Writing the extended matrix as with the quotient block , the row equations at become
The verifier batches the rows with the equality weights . For machine define its local -weighted row combination , and similarly for the quotient block; the batched target is . Let be the multilinear extension of , and let , denote the next-level witness-table coordinates of and . The full batched claim is
Compared with the single-machine claim , the distributed claim simply partitions both witness-dependent factors. Machine owns a subset of the next-level witness table and the matching restriction of the row-batched weight, so no machine materialises the full witness table or the full weight function. In the subsequent sum-check the same decomposition holds round by round: each machine computes the round-polynomial contribution for the coordinates it owns, and the machines aggregate only the small round-polynomial coefficients. The verifier sees the same batched claim as in the single-machine protocol.
Recap against the three criteria
- Distributable witness. The balanced block partition gives each machine a disjoint contiguous share, and every step — inner/outer/opening commit, the partial fold, the quotient lift, the next-level commit, and the sum-check — is computed per machine over its own blocks.
- Low communication. Only short objects ever cross machines: the -sized partial commitments , the scalar claims , the coefficient-wise quotient sum, and the small per-round sum-check messages. The large items — the inner/opening digits and, decisively, the folded responses — never leave their machine. Keeping a per-machine is exactly the change that removes the one all-reduce that would otherwise dominate communication.
- Net speed-up. Per-machine is kept only for the constant block of leading (large) rounds; afterward the prover reverts to the single-machine protocol, so the witness-growth and extra fold levels are bounded and the distributed parallelism translates into an end-to-end win.
Recursion and proof streams
A fold turns an opening of a committed source into an opening of a new digit witness. The schedule selects a chain of these reductions ending in a response that the verifier reads and checks directly. This does not require the full witness to shrink at every edge; in particular, the root may expand it. The recursion here is a sequence of polynomial-opening reductions. Each step proves relations about the previous source and passes one new witness claim to its successor.
This chapter follows a direct edge with one source group first. A grouped root and an edge that offloads setup use the same handoff, with the additional claims described below.
What crosses a recursive edge
Suppose level starts with a commitment to a source table , an opening point , and a claimed value . The statement to prove is
The tilde denotes the multilinear extension of the table in this base case. The commitment fixes the source before the challenges used to check (1). At the root, the application supplies this claim. At later levels, the preceding fold supplies it.
To see where the new witness comes from, recall the common-ring case of the Akita fold. Block has inner digits and inner commitment . Its ring opening partial is . After the opening payload has been bound, the transcript supplies sparse ring challenges , and the prover forms
For two blocks, this is simply . Linearity gives . The fold also checks that the same is consistent with the two opening partials. Thus the commitment and opening checks use a common folded source.
The prover decomposes the response, partials, and inner images into short digits. Write these segments as , , and . They begin the next logical witness:
The auxiliary digits depend on the physical relation. Quotient lifting adds digits for polynomial-modulus quotients. Compressed payloads add the digits used by their compression chains, and quotient lifting also adds the compression quotients. A raw reduced-evaluation fold has neither kind of auxiliary data. The complete witness layouts define the segments for each admitted case.
The response in (2) combines source blocks, but (3) includes the digitized response and all the opening, inner-commitment, and auxiliary segments. Reducing the claim to one witness opening therefore does not imply that this full witness has fewer entries than the input source. Digit decomposition and the selected physical realization can outweigh the response reduction, especially at the root. Witness length, public payload size, and the size of the claim passed onward are distinct quantities.
Equation (3) is prover state. A nonterminal fold does not send this full witness to the verifier. Instead, it binds the witness and reduces its relations to a single opening.
Bind the witness before checking it
If the successor is another recursive fold, the prover commits to using that successor's commitment parameters. Call the public payload . If the successor is terminal, the prover prepares only its inner images . Those images replace the outer commitment on the final edge.
In both cases, the transcript absorbs the outgoing binding before drawing the ring-switch challenge , the range and row points , or any Stage 1 and Stage 2 challenges. A prover must therefore choose the witness binding before learning the points that test it.
The sumcheck stages then reduce the fold's constraints. Stage 1 carries claims about the digit range image and, for the L2 route, the response norm. Stage 2 combines those checks with the ring relations and the scalar opening relation. Its final check leaves an evaluation of the same witness:
Here is the final Stage 2 point and is the prover's claimed witness evaluation. Sumcheck alone has not authenticated against the outgoing witness binding. That is the next fold's task. In the canonical coefficient representation, the handoff is
The successor opens the already-bound source at this point. Repeating (5) connects each fold's final scalar check to the next fold's commitment check. The final direct check closes the chain.
Some extension-field schedules store a deterministic tensor subfield projection of the logical witness. The successor then opens that physical representation with the corresponding point and value conversion. Equation (5) describes the logical handoff; it does not assert byte identity between the logical digit table and every committed representation.
Exact layout and padding
The layout is part of the statement being committed. For source ring elements and positions per block, the address rule is
source = block * L + position
live_blocks = ceil(N / L)
is a power of two. The final block may be partial, and its live entries
stay tight. Digits for one source element are adjacent. Recursive witness
construction consumes canonical WitnessLayout units in order, including
the scheduled chunk and auxiliary segments.
For example, and give three live blocks of lengths . This does not create two extra live source elements in the final block. Operations that need a rectangular block treat the missing positions as zero. The multilinear commitment domain may require further zero padding, whose length is derived from the exact witness length and commitment ring dimension.
Prover and verifier use that same domain when interpreting . Treating padding as live witness data, or changing the flattening order, would change the polynomial in (4).
Root groups and setup-prefix claims
The root can open several polynomials and several commitment groups. Each group has its own source geometry and opening point. The root batches their relations into one fold and constructs one outgoing digit witness. It remains a nonterminal fold even when the schedule sends that witness directly to the terminal.
A direct recursive edge carries one witness group. An offloaded edge carries two groups in this order:
setup prefix | witness
The setup prefix is a committed prefix of the public setup vector. When Stage 2 leaves a setup contribution for later verification, Stage 3 reduces that contribution to a separate opening of the selected prefix. It does not replace or change the witness claim .
The successor authenticates these two groups at their own points, then constructs its own outgoing witness. The schedule determines whether the extra prefix group exists; a mismatched prefix claim and prefix parameter set is invalid. Setup offloading derives this additional claim. The terminal accepts only the witness group, so the final edge does not carry a deferred setup-prefix opening.
Payloads and relation modes
A nonterminal fold carries an opening payload and binds its successor. Their representations depend on the schedule:
| Public value | Compressed representation | Raw representation |
|---|---|---|
| Current commitment | , the end of the B-image compression chain | B image |
| Opening payload | , the end of the D-image compression chain | D image |
| Recursive successor binding | Successor's | Successor's |
Every compressed payload in this table is 128 bytes. Raw payload lengths follow the selected matrix geometry. The successor's payload mode determines the outgoing binding, so it need not match the current fold's mode at a transition.
The root and first recursive fold use compressed payloads. Later folds that consume a setup prefix also remain compressed. A later fold without an incoming prefix may start a raw suffix; subsequent folds cannot return to compressed mode. A schedule may remain compressed throughout.
Ring-relation mode is a separate choice. QuotientLift carries quotient
digits to check native ring equations after switching to field evaluations.
An admitted ReducedEvaluation suffix checks the reduced equations without
those digits. This suffix starts no earlier than absolute level two, uses
evaluation-trace openings and direct setup evaluation, and has no incoming
setup prefix. It cannot return to quotient lifting. Both choices preserve the
handoff in (4).
The root and first recursive fold use subring coefficient packing for their opening relations. Later recursive folds use evaluation trace. In a proper extension field, evaluation-trace openings also run extension-opening reduction. These opening methods change how the current scalar claim enters the fold, not which witness evaluation Stage 2 passes onward.
The last edge and terminal
When the successor is terminal, its inner images are the outgoing binding. The predecessor absorbs their canonical bytes before its ring-switch and sumcheck challenges. The terminal response carries those same images, the ring opening partials, and the folded response .
The terminal checks the response bounds, opening consistency, A relation, and scalar opening directly. It creates no new witness commitment and has no B or D relation. Even a one-block terminal follows this path. Terminal verification derives the checks and explains how they use the predecessor's binding.
Proof anatomy and schedule ownership
The proof is one Spongefish argument stream. The validated schedule fixes the messages for one root fold, zero or more recursive folds, and one terminal fold. Each nonterminal level emits its opening payload, Stage 1 and Stage 2 data, and optional Stage 3 data in protocol order. Extension-opening reduction appears only where the field and opening method require it.
The next-witness binding has two variants. OuterPayload carries a
recursive commitment, which may be compressed or raw. TerminalInnerState
selects the final A-only handoff and carries no duplicate commitment payload.
The selected schedule fixes level count, group geometry, decomposition, payload modes, and terminal response shape. The verifier validates this message counts and byte bounds before replay. It does not run the offline planner or try a different mode when a proof fails.
The offline planner runs one root search. Root contraction can change candidate
order, but it is not a feasibility rule or part of the final objective.
A root whose complete outgoing witness is no smaller than its input remains
eligible. Contractive and noncontractive roots share the same suffix memo and
frontier.
The configured SelectionPolicyId comparator selects the final complete
schedule.
For each non-root, nonterminal candidate, the planner requires the next witness length to be strictly smaller than the current search-state length. Both lengths include auxiliary data and existing layout alignment, but exclude chunk padding that depends on the consuming fold's block width. This padding adds zeros so each chunk body fits that width. The physical output can therefore be larger than the physical input even when the candidate passes this test. Root candidates do not require this decrease, even before successor padding. Terminal candidates instead satisfy the direct-response feasibility checks; they create no successor witness. Offloaded edges also enforce the explicit minimum contraction policy described in setup offloading.
Code map
crates/akita-planner/src/schedule_params/candidate/recursive.rschecks recursive candidate contraction and derives terminal candidates.crates/akita-planner/src/schedule_params/suffix_dp.rsrecords the successor-aligned physical lengths and checks offloaded-edge contraction.crates/akita-cpu-backend/src/opaque/recursive/commit.rsprepares the successor's physical witness, commitment, or terminal inner state.crates/akita-types/src/proof/levels.rsdefines the level records and successor-binding variants.crates/akita-verifier/src/fold/mod.rsbinds the successor before replaying ring switching and the sumcheck stages.crates/akita-verifier/src/fold/suffix.rscarries the resulting point and value into the next fold, andcrates/akita-verifier/src/fold/terminal.rsvalidates terminal-state identity.crates/akita-pcs/tests/transcript_hardening.rschecks transcript agreement and the ordering of the final witness binding.
Setup offloading
Setup offloading reduces the amount of public setup data that the verifier must scan during an opening. Akita prepares commitments to selected setup prefixes in advance. During the proof, the prover shows that a claimed setup contribution comes from one of those prefixes. A later fold authenticates the resulting opening against the prepared commitment.
This feature is part of the current recursive setup path. It is selected by an
expanded schedule row loaded from a trusted external .aks artifact. Once that
row is resolved, a caller cannot add or remove an offloaded edge.
The setup work inside a fold
Each nonterminal fold checks relations that use the public A, B, and D matrices. At the verifier's sampled point, those matrices contribute one weighted sum of setup coefficients. Akita calls this value the setup contribution.
The verifier can obtain the value in two ways.
| Mode | What happens during verification | Extra proof work |
|---|---|---|
| Direct | The verifier scans the active public setup prefix and computes the weighted sum. | None. The value is checked inside Stage 2. |
| Offloaded | The proof supplies the setup contribution. Stage 3 proves that it is the correct weighted sum, then leaves one opening claim for a committed setup prefix. | One setup product sumcheck and one carried setup prefix opening. |
Direct mode keeps the proof smaller, but its scan grows with the setup used by the fold. Offloaded mode replaces that scan with preprocessing and proof work. It is useful only when the later recursive opening costs less than the direct scan it removes.
What a setup prefix is
The public setup is one flat vector of field elements. A fold reads an initial part of that vector as its A, B, and D matrices. The active part may not have a power of two length, while a multilinear commitment needs a power of two domain.
Akita therefore records two lengths for each prepared prefix:
natural_lenis the number of setup coefficients that can receive nonzero weight in the fold;n_prefixis the complete power of two prefix covered by the commitment.
The setup builder commits to all n_prefix coefficients. Coefficients after
natural_len are real setup values, not zero padding. The Stage 3 weight is
zero outside natural_len, so those extra coefficients do not change the
claimed setup contribution.
The commitment block geometry covers exactly n_prefix / d_A setup rings.
Artifact admission, serialized slot registries, and prover setup all
reject a prefix profile that covers only the natural support or leaves a
partial final block.
A SetupPrefixSlotId binds the active length and the commitment profile. That
profile fixes the commitment domain, inner and outer matrices, ring dimensions,
and decomposition parameters. The scheduled incoming prefix also fixes how its
opening will be proved. Prover and verifier registries must contain the exact
set of slots required by the admitted schedule rows.
The recursive handoff
An offloaded fold produces two independent claims:
- Stage 2 produces an opening claim for the next folded witness.
- Stage 3 produces an opening claim for the selected setup prefix.
The successor fold receives both claims as ordinary commitment groups. The setup prefix is a precommitted group. The folded witness is the new witness group. Each group keeps its own opening point, and the grouped opening protocol authenticates both against their commitments.
prepared setup prefix S
|
v
fold i: Stage 2 checks the witness relation
Stage 3 proves the claimed setup contribution
|
+--> opening of the next witness
+--> opening of S at the Stage 3 point
|
v
fold i + 1: authenticate both openings in one grouped fold
The witness claim and setup claim never become one point or one value. Stage 3 does not change the witness point produced by Stage 2. A fold may consume a setup opening from its predecessor while producing another setup opening for its successor.
The terminal fold cannot offload its setup contribution. It has no successor that could authenticate a new setup opening, so it always performs its final checks directly.
What Stage 3 proves
Stage 2 prepares one checked SetupContributionPlan. The plan describes the A,
B, and D setup rows, their witness weights, and the powers of the ring challenge
used at the sampled relation point.
In direct mode, the verifier uses this plan to scan the public setup. In offloaded mode, Stage 2 accepts a claimed value, and Stage 3 prepares the same plan again from the Stage 2 challenge point. The prover and verifier then run a degree two sumcheck over two coordinates:
- one coordinate selects a coefficient inside a setup ring; and
- one coordinate selects the setup ring within the flat prefix.
At the final point, the verifier checks the product of three evaluations:
setup prefix value
× setup index weight
× power of the ring challenge
This is a setup only proof. It does not include the next witness claim. The detailed polynomial identity is in Sumcheck stages. The exact mixed dimension evaluation rules are in Setup contribution and Stage 3.
How the planner chooses offloading
The ordinary configuration catalogs use direct setup evaluation. A supported
RecursiveCommitmentConfig<Cfg> expects a separate external catalog in which
the planner may use setup offloading.
For each nonterminal edge, the planner retains a direct successor. At producer levels admitted by the catalog's recursive setup search policy, it also compares an offloaded successor:
Direct successor: [folded witness]
Offloaded successor: [setup prefix, folded witness]
The planner keeps an offloaded edge only when all of the following are true:
- setup construction can prepare the exact prefix commitment;
- the successor can open the prefix and witness together;
- the complete folded witness contracts by at least a factor of three; and
- the offloaded suffix reduces the power of two capacity of the first setup scan that still runs directly.
Among feasible recursive schedules, the production policy first minimizes the power of two capacity that covers all setup objects. It then minimizes the first setup capacity that the verifier still scans directly. Within those capacity buckets, it compares the exact proof-and-work score, then estimated proof bytes, including every Stage 3 proof, and the first direct output-witness length. The canonical descriptor breaks remaining ties.
The shipped recursive catalogs consider offloaded edges produced by the root
and its direct child. This RootAndFirstChildV1 domain is part of the catalog
identity; direct traversal remains available at every level. Exhaustive search
is available for audit workloads. Within the selected domain, the planner may
select no offloaded levels, one level, or several levels. A prefix size does
not force the choice. The successor's incoming_setup_prefix field records the
selected edge. There is no second producer-side mode bit that can disagree
with it.
Planner search happens offline. The artifact row records the exact choices, and the verifier resolves and audits that row. It never searches for a cheaper schedule while checking a proof.
Current supported configurations
The recursive catalog is intentionally narrower than the ordinary Akita catalogs. The current build can expose recursive setup schedules for:
- the fp32, fp64, and fp128 dense configurations;
- the fp128 one hot configuration;
- the fp128 one hot multi chunk configuration with eight chunks and two leading
distributed levels (
OneHotMultiChunk); and - the fp128 one hot multi chunk configurations with two, four, or eight chunks
and three leading distributed levels (
OneHotMultiChunkW2R3,OneHotMultiChunkW4R3, andOneHotMultiChunkW8R3).
RecursiveCommitmentConfig<Cfg> inherits the base configuration's ring-dimension
policy. Each artifact row fixes the native A, B, and D dimensions for its folds.
Supported offloading rows can use different dimensions for these matrices and
can change dimensions between folds. A ring dimension is the number of field
coefficients in one ring element; it is not a matrix row count.
For example, one row in fp128_onehot_recursive.aks has two earlier commitment
groups, each with one 16-variable polynomial. Its final group contains two
34-variable polynomials. The first recursive fold opens a setup-prefix group
with
The A and B dimensions belong to that group. The consuming fold owns the shared D dimension. The ring-dimension contract explains these roles. The matching recursive catalog must contain an admitted row for the requested workload and dimensions.
Support depends on supplying the matching recursive family artifact. Other base configurations have no recursive catalog and are rejected rather than silently falling back to a direct schedule under the recursive adapter.
The dense artifacts cover singleton polynomials with these variable counts:
| Base configuration | Recursive artifact | Variable counts |
|---|---|---|
fp32::Dense | fp32_dense_recursive.aks | 20, 22, 24, 26, 28, 30 |
fp64::Dense | fp64_dense_recursive.aks | 21, 23, 25, 27, 29 |
fp128::Dense | fp128_dense_recursive.aks | 20, 22, 24, 26, 28 |
Load the matching artifact into
TrustedScheduleCatalog<RecursiveCommitmentConfig<Cfg>>. A recursive family
allows offloading; individual rows may still select only direct edges when
that is the planner's preferred feasible schedule.
Regenerate these artifacts with the current planner:
scripts/generate-schedule-artifacts.sh --row-progress \
fp32_dense_recursive fp64_dense_recursive fp128_dense_recursive
When a grouped proof includes commitments formed earlier, those commitments are
created under the base configuration. The later grouped opening selects
RecursiveCommitmentConfig<Cfg>. This lets commitments made at different times
enter the same opening without guessing a future setup offloading schedule. A
scalar recursive profile can select the recursive adapter directly because it
has no earlier commitment groups to preserve.
What the verifier rejects
The schedule, setup, proof, and carried claims must agree exactly. The verifier rejects the proof when any of the following occurs:
- a required setup prefix slot is missing or has the wrong identity;
- the proof contains Stage 3 data for a direct edge;
- an offloaded edge omits its Stage 3 proof;
- the committed prefix is shorter than the active setup support;
- the successor has the wrong group order or opening point;
- the setup contribution plan does not match the scheduled A, B, and D geometry; or
- any checked size or offset overflows.
The transcript binds the admitted schedule, setup identity, prefix slot, group
layout, and claims before the challenges that depend on them. Malformed input
must return AkitaError or SerializationError. It must not cause a verifier
panic.
Where the implementation lives
| Responsibility | Primary implementation |
|---|---|
| Enable the recursive catalog | crates/akita-config/src/recursive_commitment.rs |
| Search direct and offloaded suffixes | crates/akita-planner/src/schedule_params/suffix_dp/ |
| Build recursive candidates and prefix requirements | crates/akita-planner/src/schedule_params/candidate/recursive.rs and candidate/setup_prefix.rs |
| Define prefix identities and proof data | crates/akita-params/src/layout/setup_prefix_slots.rs and crates/akita-types/src/proof/setup_prefix.rs |
| Build the shared setup contribution plan | crates/akita-types/src/setup_contribution/ |
| Evaluate the setup contribution at the Stage 2 point | crates/akita-verifier/src/setup_contribution/ |
| Materialize required prefix commitments | crates/akita-setup/src/recursive_prefixes.rs |
| Prove the setup product | crates/akita-cpu-backend/src/opaque/sumcheck/stage3/ |
| Verify Stage 3 | crates/akita-verifier/src/stages/stage3.rs |
| Enforce the recursive fold handoff | crates/akita-prover/src/protocol/prove/ and crates/akita-verifier/src/fold/ |
The live planner contract is
specs/setup-offloading-planner.md.
It records the exact feasibility rules and external-artifact invariants. This
chapter owns the reader explanation of the implemented feature.
Verification
How the verifier replays the proof level by level, and the no-panic contract that governs every verifier-reachable line.
Reading this section
The verifier has several checks because one recursive fold must bind a public opening claim, a digit witness, a ring relation, and the public setup at the same time. Read the chapters in this order:
- Matrix evaluation at a point defines the physical rows and columns.
- The Stage 2 fused check shows how the relation, range image, and schedule-selected opening method share one final witness evaluation.
- Evaluation trace explains the trace-based opening method. Root fold and ring switch explains subring coefficient packing.
- Setup contribution and Stage 3 explains direct setup evaluation and recursive setup offloading. Read the setup offloading overview first if you want the complete planner, preprocessing, and recursive handoff.
- The distributed relation verifier explains exact dyadic ownership and unequal chunks.
- Terminal verification explains the final direct checks after recursion stops.
The proving section owns the derivation of the ring relations and the logical multi-group layout. These verifier chapters start from those relations and explain how one verifier replays them at sampled points. This separation keeps the mathematical definition and the optimized verifier implementation from becoming competing sources of truth.
The book describes shipped behavior. The files under specs/ record design
history and pending changes, so they may describe alternatives that are not
active in the verifier.
Verifier data flow
For each nonterminal level, the verifier follows this order:
validated schedule and setup
|
v
fold replay and outgoing witness binding
|
v
ring switch: sample alpha, tau0, and tau1
|
+--> prepare relation matrix evaluator
+--> prepare compression weights
+--> prepare scheduled opening terms
|
v
Stage 1: digit range product
|
v
Stage 2: range image + relation + opening claim
|
v
Stage 3: setup product when the setup claim is deferred
|
v
next recursive level or terminal direct checks
Preparation validates public geometry once. The final point kernels then use typed prepared state and return errors for any remaining mismatch.
Per-level replay
batched_verify (in crates/akita-verifier/src/fold/verify.rs) receives
a TrustedScheduleCatalog<Cfg> already validated and bound to the verifier's
exact config. The catalog is a trusted verifier parameter. It is loaded before
proof parsing and is not read from the proof.
At a high level:
- Bind the instance and absorb the opening batch shape into the transcript.
- Resolve the exact trusted row named by
OpeningScheduleSelection. Artifact identity and row digests are checked before the orderedGroupCommitPhaseParamsvalues are compared with the resolved row. The verifier never runs planner search. - Replay the structural folds in
fold/: the root fold followed by every recursive fold, using the schedule-selectedCommittedGroupParams. - Check the terminal witness directly against its predecessor-bound
tstate. The terminal relation isconsistency | A; it has no outeru, B block, D block, or quotient sumcheck. If the terminal A matrix uses an L2 route, the verifier also computes the decoded response's exact integer squared norm and compares it with the scheduled cap.
The verifier source follows this split. fold/ holds orchestration: the root
and suffix walks, the fold-challenge draw, the fold's public relation instance,
and terminal dispatch. verify_fold in fold/mod.rs runs one
nonterminal fold as a sequence of stage calls in transcript order:
- check the opening and commitment payload shapes, then read the fold response and draw the fold challenges;
- assemble the ring-relation instance and receive the successor witness;
- replay the ring switch (
stages/ring_switch.rs) and derive the relation claim and range-image plan (stages/relation_claim.rs); - replay Stage 1 (
stages/stage1.rs), then prepare the Stage 2 opening semantics (stages/opening_semantics.rs); - replay the Stage 2 rounds (
stages/stage2.rs), then Stage 3 when the successor defers the setup contribution (stages/stage3.rs); - check the Stage 2 output claim, which needs the Stage 3 setup claim.
Each stage returns a typed replay output that the next call consumes. The
Stage 2 round replay and output check are separate calls because Stage 3 sits
between them in the transcript. relation/ holds the prepared relation
evaluator, the relation point, and the evaluation trace. terminal/ holds the
direct terminal checks and the exact A-product evaluation.
At each nonterminal fold, the verifier checks fixed 128-byte p_H and p_F
payload shapes, reconstructs the B, D, F, and H relation right hand sides, and
folds the compression relations at their native ring dimensions. It derives
the negative-binary support from WitnessLayout and evaluates the stage-1
equality table restricted to those intervals; compression roles never enlarge
or shrink the ordinary A/B/D common address block.
The same validated fold parameters select the Stage-2 ring-relation
realization. QuotientLift evaluates the factored ordinary relation and its
explicit quotient spans. ReducedEvaluation instead evaluates terminal
signed-wrap residue kernels for the A/B/D rows and the separately owned F/H
compression program; its witness layout contains no ordinary or compression
quotient spans. Both paths close the same schedule-bound native-ring statement
and feed the same next-witness opening into the successor. There is no
proof-controlled mode bit or fallback path.
Schedule validation admits reduced evaluation only as a monotone single-chunk
suffix after the first two folds and all multi-chunk folds, with
evaluation-trace openings and direct setup contribution. Folds 0 and 1 require
coefficient packing and quotient lift even when single-chunk. The reduced suffix rejects packing, incoming setup
prefixes, deferred Stage 3, and any later return to quotient lifting before
transcript replay. Raw versus compressed payload and L∞ versus L2 response security
remain independent choices within that admitted suffix.
An L2 fold at D64 or D128 also replays operator norm rejection from the transcript. The schedule fixes the sparse challenge family and both the true subset threshold and strict integer threshold. A challenge is accepted only when the integer interval calculation proves that every spectral magnitude is within the strict threshold.
Root replay reads each commitment group's point directly from
PolynomialGroupClaims.
The verifier prepares the per-group relation and extension-opening factors from
that complete point, without reconstructing a common point.
When EOR is required, the verifier samples an early coefficient vector and
replays one ordinary sumcheck for the combined opening claims. The proof keeps
the individual terminal claims. The verifier checks their early combination
against the sumcheck terminal value and absorbs them. It then absorbs the
complete opening payload before sampling the independent application
coefficients that bind those terminal claims to the committed witness.
At a recursive boundary, Stage 2 supplies the next-witness claim
(stage2_point, stage2_next_w_eval).
Stage 3 independently proves the setup product and supplies
(stage3_setup_point, stage3_setup_prefix_eval).
The successor consumes these as separate witness and setup groups.
Stage 3 does not re-randomize, project, or serialize the witness claim.
The terminal A * z check accepts exactly the signed-i16 coefficient class.
Decoded coefficients outside [-32768, 32767] are rejected before arithmetic;
there is no alternate i8 or balanced-radix verifier path. The exact
CRT-capability selector keeps the base profile when
2 * width * D * floor(q/2) * 32768 < product(base primes) and otherwise adds
the 12289 i16 tail. A schedule whose accumulation exceeds both profiles is
rejected as an invalid setup.
AkitaVerifier construction prepares the terminal matrix before any proof
arrives. It keeps one prepared entry per ring dimension, covering the longest
terminal prefix and the widest terminal row among its admitted schedule rows.
A shorter product reads a prefix of that entry, and exact CRT capacity is
monotone in the row width, so the widest row's profile is exact for every
narrower one. The entry carries the i16 tail only when the widest row needs it.
Prepared forms are derived from the coefficient setup and never serialized.
Verification only reads them, and shape and setup-prefix checks happen before
either kernel indexes prepared state.
The verifier never constructs prover-only polynomial backends or setup expansion kernels.
Schedule and profile admission
Verifier admission uses one canonical row audit. Before setup access or proof replay, it:
- validates the trusted artifact family, protocol epoch, active policy, and runtime challenge hooks when the catalog is installed;
- resolves the fixed-width row digest by bounded lookup;
- checks every ordered public committed profile against the resolved row;
- re-audits every A, B, D, recursive, and terminal SIS matrix against the canonical security table, role, modulus, rank, width, bound, and ring dimension;
- checks root, recursive, setup-prefix, challenge, witness-partition, terminal response, and full terminal norm cap geometry;
- checks that the schedule fits the setup field capacity; and only then
- binds the instance descriptor and replays the proof.
Private polynomial representations and honest-prover witness models are absent from this path. The public selection is one digest of the exact ordered profiles and expanded row. Catalog policy metadata is validated when the trusted parameter is loaded. Unknown proof row digests reject. There is no proof field that can replace a catalog row or ask the verifier to decode schedule content.
The verifier no-panic contract
Verifier-reachable execution is a no-panic boundary.
Malformed verifier-facing proof, setup, schedule, public claim, opening point,
commitment, direct witness, or transcript input must be rejected with
AkitaError or SerializationError, never by panicking.
AkitaError has one canonical definition in akita-error.
Crates in scope
akita-verifier- Verifier-reachable paths in
akita-types,akita-serialization,akita-algebra,akita-sumcheck,akita-transcript,akita-challenges, and verifier-usedjolt-fieldcode akita-config(everyCommitmentConfigmethod reachable frombatched_verify)akita-schedulesartifact identity, row resolution, and canonical resolved-row audit paths
Rules for contributors
- Do not add verifier-reachable
panic!,assert!,assert_eq!,expect,unwrap,unreachable!, unchecked indexing, overflow-prone shape arithmetic, or unbounded allocation unless an earlier boundary has validated the invariant. - Use
akita_error::checkedfor reusable exactusizeformulas. The functions returnOption, so the caller maps failure to theAkitaErrorvariant that matches the protocol boundary. A direct standard librarychecked_*call remains appropriate for one local operation. - Do not use wrapping or saturating arithmetic for exact sizes and indices. Reject arithmetic that cannot represent the required geometry.
- Strengthen validation at deserialization, setup construction, schedule selection,
CommittedGroupParamsconstruction, and verifier API entry points rather than sprinkling checks through hot loops. - Prover-only panics are acceptable when not reachable from verifier paths.
Maintainer mirror: docs/verifier-contract.md.
Historical audit evidence: docs/verifier-panic-audit.md.
Matrix evaluation at a point
The verifier evaluates the relation matrix multilinear extension without
materializing the matrix. Its column geometry comes from the same
WitnessLayout that emitted the witness.
Every nonterminal fold proves that one flat witness satisfies a public system of ring relations. The verifier sees the public setup, the proof, and one random evaluation of that witness. This chapter explains the rows, columns, and compact evaluation used to check that system at one point.
The semantic relations
For one commitment group, four ordinary row families explain the source relations:
| Family | Purpose | Main witness segment |
|---|---|---|
| consistency | Tie the folded response to the opening digits | z_hat, e_hat |
| A or inner | Check the inner commitment image | z_hat, t_hat |
| B or outer | Check the outer commitment image | t_hat |
| D or opening | Check the opening commitment image | e_hat |
Each commitment group has its own consistency, A, and B rows. The consuming level owns one D family after it combines all group opening digits. A group may have its own opening point, polynomial count, live block count, and A and B ring dimensions. The D ring dimension belongs to the consuming level.
These four families are the best way to understand the mathematics. They are not always the complete production row list.
Compressed production rows
Production schedules normally use compressed commitment payloads. In that mode, the ordinary B and D targets are private intermediate values. Two compression maps reduce each group B image through F rows and reduce the level-wide D image through H rows. Only the terminal F and H payloads are public.
The physical row order is:
for each group in authenticated relation order:
consistency
A rows
B rows
level-wide D rows
for each compression map:
one F row per group
one level-wide H row
In compressed mode, the public right hand side is zero for the ordinary B and D rows and for every nonterminal compression row. The terminal F and H rows contain the fixed public payloads. Quotient-lift relation mode gives every physical row a quotient witness at that row's native ring dimension. Reduced evaluation keeps the same rows and right hand sides but omits every ordinary and compression quotient range.
RelationRhsLayout::row_families is the row-order authority. The code does not
maintain a second verifier-specific row list.
Canonical walk
WitnessLayout is the only owner of witness coefficient ranges. It orders
chunk and group units as follows:
chunk 0:
group in relation order: [Z | E | T]
chunk 1:
group in relation order: [Z | E | T]
...
optional shared ordinary quotient rows
compression digits, alignment ranges, and optional compression quotient rows
For a group with B_g exact live blocks and C chunks, chunk c owns
\left[
\left\lfloor\frac{cB_g}{C}\right\rfloor,
\left\lfloor\frac{(c+1)B_g}{C}\right\rfloor
\right).
The ranges cover the exact live prefix. They are not padded to equal length. If there are more chunks than blocks, some ranges are empty.
The three ordinary segments have different ownership rules:
Zis replicated once per chunk. An empty chunk keeps itsZrange, and the honest prover writes zero there.Eis partitioned by exact block ownership. It contains the opening digits for claims and blocks owned by that unit.Tis partitioned by the same block ownership. It contains the inner commitment images used by the B relation.
The ordinary quotient rows, when present, and the compression suffix are shared once after all chunk and group units. In reduced-evaluation mode the compression suffix contains F/H digits and alignment only.
Each unit carries an exact global block range. Relation, setup, and trace evaluators consume these checked ranges. They do not reconstruct offsets from a second chunk layout description. Multi-group and multi-chunk layouts are the ordinary product of the same two indices.
Exact block weights
For a group with exact live block count F, the fold challenge supplies F
independent sparse coefficients. The exact count is transcript bound and is
validated before any indexing. Sparse challenge values use the ring add,
subtract, and double fast paths where applicable.
What the verifier evaluates
Let tau1 select a row and let x select a flat witness coefficient. The
verifier needs the multilinear extension
\widetilde M(\tau_1,x)
=
\sum_{i,j}
eq(\tau_1,i)eq(x,j)M_{i,j}.
The ring switch challenge alpha evaluates each native ring row. The schedule
selects one of two coefficient functionals. Quotient lifting factors the common
low coefficient coordinates from x and applies powers of alpha. Reduced
evaluation contracts the exact physical equality window against a terminal
residue kernel, which already includes those coefficient coordinates.
In quotient-lift mode, the final result has three ordinary parts:
\widetilde M
=
\widetilde M_{\mathrm{structured}}
+
\widetilde M_{\mathrm{setup}}
+
\widetilde M_{\mathrm{quotient}}.
The compressed F and H contribution is prepared separately and added by the Stage 2 verifier. This keeps the ordinary A, B, and D setup geometry unchanged.
In reduced-evaluation mode there is no quotient term and no outer common-alpha factor:
\widetilde M
=
\widetilde M_{\mathrm{structured,reduced}}
+
\widetilde M_{\mathrm{setup,reduced}}.
The separately prepared compressed F/H contribution uses the same reduced functional and is added once.
Reduced evaluation at the final point
The prover uses the public residue weights derived in Checking ring relations over a field. The verifier only needs their weighted sum at the final Stage 2 point. It can compute that sum without constructing a kernel for every setup column.
Let be the complete final witness point. Consider a native coefficient window of length beginning at physical address . Its exact equality weights are
where the address is represented in Boolean bits. For a public multiplier , the required contraction is
This changes the order of the two sums. The vector contains the signed shift weights for this window. The code calls it the terminal residue kernel; here terminal means the final sumcheck point, not the terminal fold. The same signed-wrap recurrence gives
Preparing takes field operations and storage. The verifier reuses it for multipliers with the same checked coefficient window and contracts their coefficients during the combined A/B/D setup scan. Different windows can require different vectors even when their dimensions agree. The F/H compression maps use their separate relation evaluator with the same reduced semantics. This calculation does not remove the work of reading the active public setup coefficients.
The window above is the contiguous case. More generally, let be the actual physical witness address of coefficient in one native digit polynomial. Use
WitnessLayout determines these addresses, including group, chunk,
subcolumn, and digit placement. The earlier formula has
. Apply the same contraction to each digit term
with its public gadget and row factors. When multiple terms reference the
same witness coordinate, their public weights add at that address; a later
contribution must not replace an earlier one. The row construction
uses the same address rule.
Structured witness terms
The structured term covers the non-setup coefficients of the consistency, A, B, and D rows. Its inputs include:
- sparse fold challenges evaluated against the mode-selected coefficient functional;
- opening point weights for source positions and live blocks;
- gadget weights for the A, B, and D decompositions;
- exact group, claim, chunk, and block ranges from
WitnessLayout; and - row weights from the
tau1equality polynomial.
The evaluator stores compact affine descriptions of these axes. It does not materialize a matrix row or a dense witness-sized weight vector.
Setup term
The setup term covers A * Z, B * T, and D * E. One
SetupContributionPlan owns the setup address geometry for all three roles.
It supports two ways to obtain the same value:
- Direct mode scans the required public setup prefix during Stage 2.
- Deferred mode uses a claimed setup value in Stage 2 and checks that value in Stage 3.
The mode changes where the setup inner product is checked. It does not change the relation polynomial.
Reduced evaluation is admitted only with direct setup contribution. The plan prepares one terminal residue functional for each distinct checked native coefficient window, then reuses the existing fused A/B/D traversal with those weights. It does not create one kernel per setup lane or scan the three roles separately.
Quotient term
In quotient-lift mode, each physical row has quotient digits for division by
X^D + 1 at its native ring dimension. The verifier evaluates those explicit
digits and multiplies by the row weight and the evaluated denominator.
Compression quotient rows are handled by the separate compression evaluator
and are not counted twice. Reduced evaluation has no quotient term; the signed
wrap contribution is already present in the terminal residue functional.
Setup roles and mixed rings
The A, B, and D setup contributions use the same group and chunk ranges. D
group offsets follow checked relation-group prefix sums.
SetupProjectionGeometry owns mixed-ring projection, so verifier evaluation
does not maintain a parallel setup-column layout.
The active
role-native-projected-digit-layout
spec defines the E and T verifier cutover. Its target physical order is:
[semantic value][role subcolumn][role digit][native coefficient]
The setup matrix and relation witness use the same subcolumn and digit axes.
In quotient-lift mode, a role subcolumn s of dimension r has weight
alpha^(s * r). In reduced mode, the checked physical window selects the
corresponding entries of the terminal residue functional. Both modes apply the
role gadget power on the digit axis.
When the projection ratio is one, the verifier does not allocate projection powers or multiply by one. It uses the unprojected contiguous equality window directly. Mixed groups use exact coefficient ranges and the shared minimum relation block. There are no carrier spans or per-role padding to scan.
The A, B, and D roles may use different ring dimensions. The verifier chooses
their greatest common coefficient block as the low coefficient boundary. A
role of dimension d_R then has d_R / d_0 relation lanes.
RelationAddressGeometry owns this split. SetupProjectionGeometry owns the
matching setup projection. The verifier never pads a smaller role to a larger
carrier ring. It applies the appropriate alpha power to each native role lane
and uses the same flat witness address for direct and deferred setup checks.
Preparation and evaluation
Ring-switch preparation validates all public geometry before it creates a
RelationMatrixEvaluator. The prepared object keeps only succinct state:
- sparse challenges evaluated at
alpha; - source-position opening evaluations;
- expanded row equality weights;
- checked relation address geometry; and
- the shared
WitnessLayoutand group metadata needed to build setup tensors.
At the final Stage 2 point, evaluate_relation_at_point dispatches once on the
authenticated relation mode. The quotient branch obtains the direct or
deferred setup term, evaluates the quotient tail, and applies the common low
coefficient factor. The reduced branch rejects deferred setup, evaluates the
structured and fused direct-setup terms with terminal residue kernels, omits
the quotient tail, and returns the already complete flat MLE.
The verifier never materializes dense relation weights. Dense verifier tables exist only as test oracles. The prover's reduced mode does use one ephemeral dense Stage-2 weight table; it is not a verifier allocation or proof field.
Safety contract
Before evaluation, the verifier checks the opening dimensions, group-local
layout, unit ranges, setup geometry, and work bounds. Malformed proof data
returns AkitaError. Verifier-reachable evaluation does not panic or allocate
from an unchecked proof-controlled dimension.
All row counts, native dimensions, address products, and allocation sizes are also checked before use.
Direct setup evaluation is linear in the public setup prefix because those
coefficients are arbitrary and must be read. Structured terms are linear in
their explicit challenges and any live quotient digits, with logarithmic
equality contractions over repeated affine address axes. Reduced preparation
uses O(d) auxiliary extension-field state for native ring dimension d and
the same single setup scan. The verifier never scales with the prover's
materialized relation table.
Code map
- Row families and public right hand sides:
crates/akita-types/src/proof/relation.rsandcrates/akita-params/src/layout/relation_layout.rs. - Witness ranges:
crates/akita-params/src/witness.rs. - Relation address geometry:
crates/akita-params/src/layout/relation_address.rs. - Residue and terminal coefficient functionals:
crates/akita-algebra/src/ring/residue.rs. - Verifier preparation:
crates/akita-verifier/src/relation/mod.rs. - Final point evaluation:
crates/akita-verifier/src/relation/evaluation.rs. - Setup contribution:
crates/akita-types/src/setup_contribution/.
The next chapter shows how Stage 2 combines this relation value with the range image and evaluation trace.
The Stage 2 fused check
Stage 2 proves three facts about the same flat digit witness. Keeping them in one sumcheck binds them to one polynomial and one final evaluation.
The three facts are:
- The witness agrees with the Stage 1 range result.
- The witness satisfies the relation matrix.
- The opening digits encode the claimed polynomial evaluations under the scheduled opening method.
The verifier replays a degree three sumcheck over the complete relation witness domain.
Input claim
Let eta be the batching challenge for the range image. Let R(tau0) be the
Stage 1 range image claim, v_M the public relation claim after row and ring
evaluation, and v_open the claimed opening value. The Stage 2 input is
\eta R(\tau_0)+v_M+v_{open}.
The transcript fixes the witness, alpha, tau0, tau1, the row batching
coefficients, and the opening claims before this sumcheck is replayed.
Final point equation
Let r be the final Stage 2 point and let w(r) be the witness evaluation
carried by the proof. The verifier checks
\eta\,eq(\tau_0,r)w(r)(w(r)+1)
+w(r)\widetilde M_{native}(\tau_1,r)
+C_{compression}(r)
+w(r)C_{method}(r).
The terms have separate owners:
EqPolynomialevaluates the range image equality factor.RelationMatrixEvaluatorevaluates the ordinary relation matrix.CompressionRelationWeightsandNegativeBinarySupportevaluate the F and H compression relations and their digit constraints.PreparedEvaluationTraceevaluates an evaluation trace opening.CoefficientPackingCompactFactorsevaluates the packed E and Q relation weights and the packing Z and direct-opening structured terms.
If eta is zero, the verifier skips the range equality evaluation. This is an
arithmetic shortcut only. The transcript and proof shape do not change.
Range image term
Stage 1 checks the range product over the same digit witness and returns a claim
at tau0. Stage 2 uses the equality polynomial eq(tau0,r) to connect that
claim to the witness value at r. The factor w(r)(w(r)+1) is the negative
binary constraint in the field convention used by the protocol.
Compressed layouts have additional negative binary digit spans in the F and H
suffix. NegativeBinarySupport evaluates the equality polynomial only over
those checked intervals. It does not allocate a dense support bitmap.
Relation term
The native relation term is
w(r)\widetilde M_{native}(\tau_1,r).
The previous chapter explains M. Direct setup mode reads the public setup
during this evaluation. Deferred setup mode substitutes the Stage 3 setup claim;
Stage 3 then prepares its setup-index weight from the same challenge point.
Compressed F and H rows are evaluated separately because their digit support and native dimensions differ from the ordinary A, B, and D roles. Their result is still part of the same Stage 2 polynomial.
Method-dependent structured terms
The relation matrix checks algebraic consistency of the witness. It does not by
itself prove that the E digits encode the opening values stated by the caller.
The scheduled method supplies that binding. Evaluation trace uses
\lambda_{trace}w(r)\widetilde T(r).
lambda_trace is the row weight assigned to the virtual trace row. The trace
is a virtual row because the verifier evaluates its public tensor formula at
the final point instead of adding a physical matrix row and quotient digits.
Subring coefficient packing has two contributions: the packed E and Q relation
weights, and two ordered structured sources, packing-Z and direct opening.
The CPU prover expands both into explicit relation events and Stage 2 term
tables from the checked group semantics. The
verifier never builds those tables. It builds CoefficientPackingCompactFactors
from the same validated packing groups, a small set of tensor families over the
block point, tail point, extension basis coordinates, and opening digit
weights, and evaluates them directly at the final point. The packing-Z weights
do not share the native A row's low alpha factor, so they remain a separate
factorized term. Every contribution still evaluates the same flat witness at
the same final point.
Why the terms share one point
All terms use the same w(r). A prover cannot use one witness for the range
proof, another for the relation, and a third for the opening claims. The shared
point also lets every verifier term consume the same checked coefficient and
address split.
Code map
- Stage 2 verifier:
crates/akita-verifier/src/stages/stage2.rs. - Stage 1 verifier:
crates/akita-verifier/src/stages/stage1.rs. - Relation preparation:
crates/akita-verifier/src/relation/mod.rs, with the relation claim incrates/akita-verifier/src/stages/relation_claim.rs. - Coefficient-packing compact factors:
crates/akita-verifier/src/coefficient_packing_relation/. - Opening semantics:
crates/akita-verifier/src/stages/opening_semantics.rs. - Evaluation trace:
crates/akita-verifier/src/relation/evaluation_trace.rs. - Prover stage:
crates/akita-cpu-backend/src/opaque/sumcheck/relation_range_image/.
The next chapter derives the evaluation trace path and explains its compact contraction. The packing equations are in Root fold and ring switching.
Evaluation trace
The evaluation trace binds each public opening claim to the E digits inside
the next witness when the schedule selects EvaluationTrace. Early folds may
select SubringCoefficientPacking instead. Both methods bind the claimed
opening in Stage 2, but they use different coefficient geometry.
The verifier never constructs the prover's trace table. It prepares a small description of each group and exact witness unit, then evaluates the trace once at the final Stage 2 point.
What the trace checks
For each commitment group, claim, and global live block, the trace combines:
- the claim batching coefficient;
- the block opening weight from the public opening point;
- the opening digit gadget weight;
- the source ring trace or packed inner opening factor; and
- the equality weight of the physical
Eaddress.
The Boolean corner values are exactly the coefficients that the prover used to
construct the opening evaluation from E. Their multilinear extension is the
public trace polynomial T used by Stage 2.
Prepared group state
PreparedEvaluationTrace stores one group record with:
- the group-local block opening point and basis;
- source and opening ring dimensions;
- the common coefficient block length;
- shared opening digit weights;
- the source ring inner trace;
- one coefficient per claim;
- one exact descriptor per nonempty witness unit; and
- a prepared contraction plan.
A unit descriptor contains the physical start of its first claim, the stride
between claims, the first global block, and its exact block count. The verifier
derives these values from WitnessLayout. It does not recompute chunk
boundaries.
Preparation also chooses the concrete contraction kernel. For a short affine range, it stores the two small block-weight tables. For a long range, it stores the exact dyadic unit segments used by the paired recurrence. Evaluation does not rebuild either plan.
Coefficient and address factors
At the final Stage 2 point, the verifier first splits off the common low
coefficient coordinates. It evaluates each source lane of the inner trace at
that coefficient point. The remaining column point selects the physical E
address.
For one claim and unit, the address is affine in these coordinates:
- local block;
- opening digit;
- source subcolumn; and
- source lane.
The block opening weight is Boolean in the global block bits. The physical column weight is Boolean in the relation address bits. A paired tensor recurrence contracts both factors without enumerating all live blocks.
Both Lagrange and monomial opening bases are supported. The monomial path uses its Boolean factor directly and does not invert a challenge.
Unequal dyadic chunks
The canonical partition does not pad chunks. A group with B blocks and C
chunks uses boundaries floor(cB/C). Unit block counts can therefore differ,
and empty units can appear when C > B.
Preparation skips empty E units. For nonempty units, the evaluator searches
for consecutive units with the same block count, claim stride, and affine
offset differences. It combines only those exact runs. Each run is divided
into power of two tensor segments. An irregular unit remains separate.
This compaction changes verifier work only. It does not change witness layout, proof bytes, transcript order, opening schedule, or protocol claims.
Concrete crossover
The paired recurrence has better asymptotic behavior for long block ranges, but a short affine scan has a lower constant cost for small ranges. The verifier uses the scan for 2 to 32 blocks per unit. It uses the paired recurrence for singleton units and for at least 64 blocks per unit.
This is a local kernel choice. Both paths evaluate the same prepared unit formula, and dense tests compare them with the materialized trace definition.
Extension field openings
When the challenge field is a proper extension of the base field, block and
position weights are stored as canonical subfield coordinates. The verifier
keeps K coordinates for extension degree K instead of expanding each value
to a dense ring of dimension D.
The trace preparation recovers the needed extension values directly from those coordinates. Invalid dimensions, coordinate counts, or noncanonical subfield images are rejected before arithmetic.
Cost
For fixed protocol dimensions, the compact path is logarithmic in the block range of one affine unit. Its explicit outer work is proportional to groups, claims, nonempty unit segments, source subcolumns, and source lanes. The chunk count is capped at 64.
The verifier stores no witness-sized trace table and no dense block basis table.
Code map
- Verifier preparation and contraction:
crates/akita-verifier/src/relation/evaluation_trace.rs. - Shared checked trace geometry:
crates/akita-types/src/trace_weight/. - Exact
Eaddresses:crates/akita-params/src/witness.rs. - Paired tensor model and kernels:
crates/akita-algebra/src/offset_eq/tensor_pair/. - Ring and subfield trace primitives:
crates/akita-types/src/field_reduction.rs.
The next chapter explains how the same relation geometry drives direct setup evaluation and the deferred Stage 3 check.
Setup contribution and Stage 3
This chapter gives the verifier details. Read Setup offloading first for the complete lifecycle and the planner decision.
The relation matrix contains products with the public A, B, and D setup
matrices. The verifier can check those products directly during Stage 2 or
defer the public setup inner product to Stage 3. Both modes use one
SetupContributionPlan and one relation formula.
One plan for three setup roles
The setup contribution contains:
A setup columns paired with Z weights
B setup columns paired with T weights
D setup columns paired with E weights
The plan derives every role from the same checked inputs:
- authenticated group order and row ranges;
- exact chunk and block ranges from
WitnessLayout; - native A, B, and D ring dimensions;
- decomposition gadgets;
- the prepared relation address point; and
- the ring switch challenge
alpha.
There is no separate Stage 3 layout and no verifier-only copy of the setup address rules.
Structured role weights
For each group and nonempty unit, the plan builds paired equality tensors for the role columns and relation witness addresses. The main axes are claims, blocks, digits, native role subcolumns, and setup rows.
Equal affine units can be combined into one extra unit axis. Before combining them, the plan checks the complete axis shape, scalar, and setup and relation offset strides. Unequal dyadic units keep their original families. No physical padding is introduced for the optimization.
Mixed dimensions
Let d_0 be the common coefficient block and let a role use ring dimension
d_R. Its projection ratio is q = d_R/d_0.
For q = 1, the plan evaluates the relation equality directly. For q > 1,
it factors aligned low relation coordinates once. If the physical relation
offset is not aligned, it records an explicit dense role projection axis. The
setup side and relation side therefore use the same native role interpretation
without padding smaller rings.
The prepared state records whether a batch is still in native coordinates or
has already factored the relation coordinates. This state is encoded by the
ProjectedEqPairTensor enum, so evaluation cannot apply the transform twice.
Direct Stage 2 mode
In direct mode, the verifier moves the plan into a DirectScan together with
the prepared coefficient functional. The scan owns the plan, the per-group E,
T, and Z column weights, and the packed D, B, and A segment partition; the plan
itself carries no functional state. DirectScan::evaluate_direct walks the
required public setup prefix. For each setup ring it evaluates the ring against
the functional (the powers of alpha in quotient-lift mode), multiplies by the
structured index weight, and accumulates the result. The structured group terms
reuse the same cached column weights. Because every evaluation reads the plan
the scan owns, a scan cannot be evaluated against a different plan.
The scan is linear in the required public setup size. This is necessary because the setup coefficients are arbitrary. The verifier factors the setup equality table by contiguous outer blocks to avoid repeated index division and repeated outer equality multiplications.
Direct mode returns the setup contribution as part of
RelationMatrixEvaluator::eval_flat_at_point.
Deferred Stage 3 mode
In deferred mode, Stage 2 receives a claimed setup contribution. It uses that
claim in the same relation evaluation, evaluates the structured group terms in
closed form from the plan, and builds no DirectScan.
Deferred mode exists only for quotient-lift levels. A deferred claim exists
only when the next fold consumes this level's setup prefix, and schedule
validation admits no such successor after reduced evaluation. The trusted
schedule, not the proof, fixes this combination, so the verifier rejects a
reduced-evaluation level with a deferred claim with InvalidSetup before any
setup planning.
Stage 3 then proves a product over two coordinates:
rho_yselects the coefficient inside a setup ring;rho_setup_idxselects the setup ring index.
At the final Stage 3 point, the verifier checks
setup(\rho_y,\rho_{setup})
\cdot
weight(\rho_{setup})
\cdot
pow_\alpha(\rho_y).
The first factor comes from the public setup or from an authenticated setup
prefix opening. The second factor is SetupIndexWeightMle, the compact MLE of
the setup-index weight. Stage 3 builds it from a SetupContributionPlan
prepared from the same Stage 2 challenge point and witness layout, so it uses
the same address rules as the Stage 2 plan. The plan keeps the group's live
witness units, and the B-role tensors are rebuilt from those, so the
constructor takes the plan alone and cannot be handed a second layout. Only
the verifier builds these
paired-equality tensors; the prover materializes the dense setup-index weights
instead. The final factor evaluates the powers of alpha inside one ring.
When a setup prefix is selected, the first factor is an evaluation of the actual
full power-of-two setup prefix S[0..n_prefix]. The active support
natural_len belongs to the setup-index weight: rows outside that support have
zero weight even though the committed setup coefficients in the tail are real.
The Boolean setup-product claim is therefore unchanged, while the deferred
opening claim is bound to the full-prefix commitment.
Stage 3 returns the full challenge point for the recursive suffix. It does not replace or modify the next witness claim produced by Stage 2.
Setup prefix offloading
A schedule may select an authenticated setup prefix slot. The verifier checks that the selected slot covers the active setup length required by the plan and the full power-of-two prefix needed by its commitment domain, absorbs the slot identity, and uses the proof's setup prefix evaluation. Recursive Stage 3 requires this selected slot and carried evaluation; direct setup contribution does not execute Stage 3.
The slot changes where the public setup polynomial is opened. It does not change the setup index weights or relation geometry.
Safety and ownership
Plan construction checks every role dimension, projection ratio, row span,
unit range, and address product. It also rejects a relation address that cannot
be bridged from the relation base to the Stage 3 setup base. Stage 3 prepares
its plan and SetupIndexWeightMle only from the exact Stage 2 challenge point.
The main implementation owners are:
crates/akita-types/src/setup_contribution/for the functional-free plan, its geometry and relation-column tensors, and the dense setup-index weights the prover consumes;crates/akita-verifier/src/setup_contribution/for the direct scan, structured group contraction, andSetupIndexWeightMle;crates/akita-verifier/src/relation/evaluation.rsfor direct or deferred selection; andcrates/akita-verifier/src/stages/stage3.rsfor the setup product check.
The distributed relation verifier
Status: verifier design and implementation guide. This chapter explains the relation produced by the distributed prover, the work required from one verifier, and the implementation that evaluates exact E/T block ranges without padding. Every Z response retains the same full ambient width.
A note on the name. "Distributed verifier" would be a misnomer: nothing about the verification is distributed. There is a single verifier, running on one machine, doing the ordinary amount of work. What is distributed is the prover — several machines cooperate to produce the proof, each holding only a slice of the witness (see the distributed prover). This chapter is about that single verifier checking the relation that a distributed prover produces. Hence "distributed-relation verifier", not "distributed verifier".
In the distributed-prover protocol several machines cooperate to prove a single Akita opening, each holding only a slice of the witness. We assume machines (the canonical choice; the distributed prover fixes this). The relation matrix the verifier evaluates is therefore no longer the single-machine but the virtually shared horizontal concatenation
where each is a single-machine-shaped relation block restricted to the blocks owned by machine . The rows of are unchanged and shared across all — this is a horizontal stacking, same row blocks, partitioned columns. Consequently every component of the single-machine now appears as column-repetitions, and the verifier evaluates each component once per machine and sums.
The implementation represents these machine slices as witness chunks. Chunk
owns the same exact block range . WitnessLayout is the
source of truth for the chunk range and for every physical Z, E, and T
address. The verifier does not reconstruct a second partition from the machine
count.
Read this chapter together with Matrix evaluation at a point. That chapter defines the production row families, witness order, and compact evaluator. This one keeps the original component-by-component derivation and explains how each component changes when the prover splits the witness into chunks. One distinction recurs throughout and is worth fixing up front:
- Partitioned segments (, ). Machine owns the blocks , so its cover only blocks. The union over machines is the full (resp. ); the repetitions tile the same data, so their combined cost equals the single-machine cost.
- Replicated segments (). Machine 's partial fold sums over its blocks but lands in the full ambient fold space (the same dimension as the single global fold). The repetitions are full-size copies — the deliberate price the protocol pays to avoid an all-reduce of the fold.
The shared A rows act on the sum of these replicated responses. Accordingly, schedule admission multiplies the exact one-chunk digit-difference envelope by before selecting the A-role SIS row. This check is performed before transcript replay; an undersized A row is rejected.
The verifier does not evaluate independently sampled A/B/D
matrices: the chunks use column views of the same setup. Chunking does,
however, create more column intervals and repeated full-width Z contributions,
so its concrete setup scan and bookkeeping cost grows with the response-chunk
count. This is why the count is both a schedule parameter and a verifier-capped
resource. Relation replay lives in
crates/akita-verifier/src/relation/evaluation.rs.
Prepared setup geometry and the shared setup scan live in
crates/akita-types/src/setup_contribution/.
When equal chunks apply, we write for the number of live blocks one machine owns. This is a power of two exactly when the chosen machine count divides exact live and the quotient is a power of two. The common root case has , but recursive levels may have and therefore use residual-aware chunks.
What the verifier needs to compute
The target is identical in form to the single-machine verifier:
The row axis is unchanged by chunking. The ordinary relation has the
consistency row, the A/B/D commitment rows, and the quotient rows.
Compressed schedules also have F and H rows and their quotient rows.
Chunking does not duplicate any of these rows. The verifier precomputes one
row_weight[i] = eq(i, r_row) per validated row. Each machine writes into the
same rows, so each row weight is applied once after summing across machines.
The formulas below focus on the ordinary structured and setup contributions. The Stage 2 fused check explains how the compression rows join the same final equation.
What changed is the column axis: the columns now enumerate the machine witnesses. Splitting the column sum by machine,
and each machine's inner sum is structurally one of the single-machine components, restricted to machine 's data and placed at machine 's column offset. So the whole chapter reduces to: take each single-machine component, instantiate it times, and sum — with the partitioned/replicated distinction deciding whether " times" costs more.
Connection to the witness and witness shape
The block partition
The machines split into deterministic, public, contiguous subsets
so every range has either or blocks. When divides , this is with blocks each. Define and . When , some consecutive boundaries are equal and those machines own empty ranges. The public matrices , , are column views of one seed-expanded matrix, so every machine regenerates the same public columns locally — the fact that keeps the verifier's dominant cost flat.
The witness layout is grouped by machine
This derivation fixes one commitment group so that the machine axis is clear.
With several commitment groups, WitnessLayout places chunks first and groups
in authenticated relation order inside each chunk. The same formulas apply to
each group with its own point, claims, dimensions, and block range. The
matrix evaluation chapter defines that complete
physical order.
The distributed prover assembles the next-level witness one machine block at a time: machine contributes its local witness as a single contiguous unit, and the lone summed quotient tails the whole thing (see the distributed prover, "Ring-switch lift and next-level commitment"):
[ z^(0) | e^(0) | t^(0) ][ z^(1) | e^(1) | t^(1) ] … [ z^(M-1) | e^(M-1) | t^(M-1) ][ r ]
└─────── w_0 ───────┘└─────── w_1 ───────┘ └──────── w_{M-1} ────────┘
So the contiguous unit is the machine block , not the component. A single
component — say e_hat — is therefore not one fused region: its
pieces are scattered through the
witness, one inside each . Machine 's and machine
's sit between consecutive e-pieces. That gap — "the
space related to other stuff" between e^(0) and e^(1) — is the normal shape,
and it does not complicate the verifier.
Why the gaps between same-component pieces are a non-issue
The single-machine verifier already evaluates e_hat, t_hat, z_hat, and
r_tail at four different offsets inside the witness; it never relies on a
component being one giant block. Each per-component evaluator from
Matrix evaluation at a point is parameterized by its
segment's start offset (e_start, t_start, z_start) and peels the block
window relative to that offset, using the at-most-one-carry split to absorb any
misalignment.
The distributed layout changes nothing structural here. It has offsets for each component, one per machine block. Let and let be the prefix-sum offset of machine block . Its pieces start at
(plus the witness's base offset). The verifier evaluates each piece at its own offset and sums. Prefix sums are required because varies with .
Each piece keeps its single-machine internal axis order, with the block sub-axis
shrunk to for the partitioned e/t pieces:
| piece | size | axis order (outermost → innermost) | kind |
|---|---|---|---|
e_hat^(j) | do · C · B_j | dig → claim → block_local | partitioned |
t_hat^(j) | do · n_A · C · B_j | a_row → dig → claim → block_local | partitioned |
z_hat^(j) | dc · df · num_positions_per_block | dc → df → blk | replicated |
r_tail | rows · levels | level → row (single) | shared |
The machine index is not an axis inside a piece — it is the outer grouping that
selects which block (hence which offset) a piece lives in. The e/t block
sub-axis shrinks from B to B_j because each machine holds only its assigned
blocks. The z block sub-axis stays the full num_positions_per_block because
the fold is replicated, and z_hat^(j) is repeated times. If
, the e_hat^(j) and t_hat^(j) pieces are empty while z_hat^(j) keeps
its full width. The honest prover writes zero in that z_hat^(j) piece.
The "global block" point now reads cleanly off this layout: inside
e_hat^(j)the block index restarts atblock_local ∈ [0, B_j), but it names the global blockblk_g = s_j + block_local, which is what the folding challengec_αis indexed by (see the e-tensor section).
Exact partitions and the equal-width special case
The production verifier accepts every canonical exact partition. It skips
empty E and T pieces. It evaluates short irregular pieces as checked affine
intervals and long repeated geometry with paired equality tensors. It never
pads a shorter chunk or materializes a dense witness-sized equality table.
The simple derivation below applies when every equals the same power-of-two value . In that case the verifier can peel the block window exactly as in the single-machine case. This remains an important special case because it makes the two-carry structure explicit.
One eq_low table still serves every machine — and this holds regardless of the
per-machine offsets, despite the gaps. The eq_low table is just the equality
weights over the low bits of ; it
depends only on and the window size, never on where a segment
sits. A segment's offset enters only as two per-machine scalars: the in-window
shift (which
sets the carry split) and the high index . So a single
eq_low (window ) is reused by every e_hat^(j) and
t_hat^(j), and a single eq_low_z (window num_positions_per_block) by every z_hat^(j);
the offsets differing per machine is fine.
Within one machine, e_hat^(j) and t_hat^(j) are spaced by
, a multiple of
, so they share the same in-window shift and carry split — which
is why machine 's t_hat reuses machine 's e_hat block summaries (the
single-machine e/t sharing, now per machine). Across machines the shifts may
differ, but each machine covers different blocks (different c_α values) and so
needs its own summaries anyway.
What does grow with are the cheap high factors. The E, T,
and Z address descriptions gain a chunk axis. These factors are prepared
once. They do not cause more setup-ring evaluations.
The exact path does not require equal chunks. Equal power-of-two windows only allow the simplest combined tensor. The closing partition section explains how the verifier handles every other canonical shape.
Tensor components
Three row blocks act with separable (tensor-product) structure — the
e_hat-consistency component (on the consistency row), the t_hat-consistency
component (on the A-rows), and the z_hat in-block consistency (on the
consistency row). Each now appears times. We work e_hat in full and
let t_hat/z_hat follow.
e-related tensor components
This is the consistency component , tying e_hat to the
stage-1 challenge combination. It sits on the single consistency row , so
row_weight[i] multiplies the sum of all machine contributions,
once, at the end.
The cell formula (per machine)
Machine 's e_hat^(j) cell is indexed by (dig, claim, block_local) with
block_local . Its local column coordinate is
the global column is , and the entry is
where is the global block index. Three things differ from the single-machine cell: (i) the block window is , not ; (ii) the consistency challenge is read at the global block , so the verifier indexes the same full table at machine 's slice; (iii) the offset is machine 's . As in the single-machine case, couples claim and block, so it does not factor into separate per-claim and per-block scalars.
Why the global block, and why . The folding challenges are a single global vector that the verifier samples once, indexed by global block. Machine gets no fresh randomness — it uses the slice (the row of in the distributed prover's partial root relation). The scalar that multiplies a fold block is the challenge for that block, and blocks are numbered globally. A column of
e_hat^(j)is addressed by the local index , but it represents a global block; because owns the contiguous range , the global index is its base offset plus the local position: . Writing would be wrong — it would name a block on machine . Concretely with , , machine starts at , so its local block is global block and carries . Reading at the global block is also what keeps the block scan equal to the single-machine cost: every global block is visited exactly once, only reordered into chunks of their exact .
The naive evaluation
acc = 0
for j in 0..M:
for dig in 0..do:
for claim in 0..C:
for block_local in 0..B_j:
blk_g = s_j + block_local
c = block_local + B_j*(claim + C*dig)
acc += row_weight[i] * c_alpha[claim][blk_g] * g_open[dig]
* eq(e_start[j] + c, r_col)
Because , the triple-plus-machine loop costs
, the same total as the single-machine naive
scan, plus a dense eq table. Empty pieces do no work.
Equal-width derivation: per-(machine, claim) block summaries
When the equal-width condition holds, peel the
block window exactly as single-machine, now per
machine. Split ;
the low part produces at most one
carry, and the equality factors into eq_low (the shared low-window table) and
eq_high_e. Because couples claim and block, build a two-bucket
summary per (machine, claim):
# Per-(machine, claim) block summaries — O(M * C * B_loc) = O(C * B):
for j in 0..M:
for claim in 0..C:
S0[j][claim] = 0 # carry = 0
S1[j][claim] = 0 # carry = 1
for block_local in 0..B_loc:
blk_g = j*B_loc + block_local
s = e_lo[j] + block_local # e_lo[j] = e_start[j] mod B_loc (per machine)
if s >= B_loc:
S1[j][claim] += c_alpha[claim][blk_g] * eq_low[s - B_loc] # eq_low shared (r_col low bits)
else:
S0[j][claim] += c_alpha[claim][blk_g] * eq_low[s]
The outer combine runs over the small axes, per machine:
# Outer combine — O(M * C * do):
acc = 0
for j in 0..M:
for dig in 0..do:
for claim in 0..C:
q = e_hi[j] + claim + C*dig
acc += g_open[dig] * (S0[j][claim]*eq_high_e[q] + S1[j][claim]*eq_high_e[q+1])
acc *= row_weight[i]
Cost
The block summaries cost — the same total block scan as the single-machine component, merely grouped into buckets. The outer combine costs , which is the single-machine but on the small digit axis. Total
versus single-machine : the heavy block term is unchanged; only the light digit term scales with .
The production kernel obtains the same result from compact affine intervals or paired tensor families. Consecutive exact units may share one chunk axis only when their block count, scalar, axis shape, and address strides match. Other units remain separate. The dense loop above remains a definition and a test oracle, not the production fallback.
t-related tensor components
The per-A-row consistency component is the same check
applied once per row of A, so it occupies the A-rows, each with its own
row_weight. Like e_hat, it is now -fold, and on each machine it is
block-diagonal in the a_row axis.
The cell formula (per machine)
Machine 's t_hat^(j) cell is indexed by (a_row, dig, claim, block_local):
with entry, on the matching a_row row,
weighted by row_weight[a_row]. This is the same claim-and-block-coupled
as the e_hat component, with the extra a_row axis tensored on.
Equal-width derivation: reuse the per-(machine, claim) block summaries
On the equal-partition fast path, the block-dependent factor
is identical to the e_hat component's. As
shown in the layout section, every e_hat^(j) and t_hat^(j) shares the same
low-window residue, so the carry split matches per machine and the per-(machine,
claim) summaries S0[j][claim], S1[j][claim] are reused unchanged — this
is the single-machine e/t sharing, extended across machines. The only new
work is the outer combine, now ranging over a_row as well:
# Outer combine — O(M * n_A * C * do):
acc = 0
for j in 0..M:
for a_row in 0..n_A:
for dig in 0..do:
for claim in 0..C:
q = t_hi[j] + claim + C*dig + C*do*a_row
acc += row_weight[a_row] * g_open[dig]
* (S0[j][claim]*eq_high_t[q] + S1[j][claim]*eq_high_t[q+1])
Cost
The summaries are shared (free here), and the outer combine costs . Total
versus single-machine : as with
e_hat, the heavy block scan is unchanged and only the cheap a_row/digit
combine scales with .
z-related tensor components
The in-block consistency contribution ties z_hat to the opening point's
in-block weights, on the consistency row (so it shares that row's row_weight,
applied with the relation's minus sign at the end). Here the replication
asymmetry bites: each z_hat^(j) is a full-size copy with the full
num_positions_per_block, not a slice, so the repetitions are
full evaluations.
The cell formula (per machine)
Machine 's z_hat^(j) cell is indexed by (dc, df, blk), blk :
global column , entry
contributed with weight . Crucially the entry does not depend on : the fold rows carry no machine-specific data (the opening weight and the gadget weights are global). Only the segment offset differs between machines.
Case 1: num_positions_per_block a power of two (root)
Peel the num_positions_per_block window per machine and build a two-bucket in-block summary
per machine (the shared eq_low_z table serves all of them):
# Per-machine in-block summaries — O(M * num_positions_per_block):
for j in 0..M:
A0[j] = 0 # carry = 0
A1[j] = 0 # carry = 1
for blk in 0..num_positions_per_block:
s = z_lo[j] + blk # z_lo[j] = z_start[j] mod num_positions_per_block (per machine)
if s >= num_positions_per_block:
A1[j] += a[blk] * eq_low_z[s - num_positions_per_block]
else:
A0[j] += a[blk] * eq_low_z[s]
# Outer combine — O(M * DF * DC):
acc = 0
for j in 0..M:
for dc in 0..DC:
for df in 0..DF:
q = z_hi[j] + df + DF*dc
acc += g_commit[dc] * g_fold[df] * (A0[j]*eq_high_z[q] + A1[j]*eq_high_z[q+1])
acc *= -consistency_weight
Because is shared, the per-machine summaries differ only by the
offset/carry split; they combine additively into one acc.
Case 2: num_positions_per_block not a power of two
The direct loop remains the semantic definition. The production verifier
represents the same addresses as a checked affine stream and contracts it
against the equality point. It does not materialize the full structured Z
segment. The work remains bounded by the size of the explicit Z axes.
Cost
| case | overhead |
|---|---|
num_positions_per_block a power of two (root) | |
num_positions_per_block not a power of two | upper bound |
This is the single-machine z-tensor — but the z-tensor is
already the cheap part of the verifier (no -evaluations), so
keeps it well below the setup-matrix floor analyzed next.
Setup components
These row blocks are the rows of the shared SIS commitment matrix, and they dominate verifier time: each entry is a cyclotomic ring element that must be -evaluated (an operation) before it can enter the scalar sum-check. The single-machine game is to perform each -evaluation once and reuse it across every product that needs it. The distributed question is whether the -fold repetition forces more -evaluations. It does not — and showing why is the crux of the equivalence claim.
The three setup row blocks, now -fold
As single-machine, three row blocks are sub-views of the same backing SIS matrix, now each repeated per machine:
D · e_hat— one_hat^(j), for . Partitioned: and , so the pieces collectively are exactly the single-machine , only re-laid-out by machine.B · t_hat— ont_hat^(j), for (per commitment group). Partitioned: collectively the single-machine .A · G_fold · z_hat— the same digit-domain matrix on each folded commit-digit vector , for , where . Replicated: one shared matrix acts on distinct full-size folds.
Why the -evaluations do not multiply
The shared SIS matrix (backing A, B, D) is regenerated from one public seed
and is identical on every machine. The verifier scans it once, exactly as
single-machine, and -evaluates each entry
r_eval(r,c) = eval_ring_at_pows_fast(matrix[r][c], α) once, because:
- For
D · e_hatandB · t_hat, the partition only re-routes whiche/tcolumn each scanned matrix column maps to. The set of matrix columns scanned — the full , the full — is unchanged. - For
A · G_fold · z_hat, all folded commit-digit vectors are read by the same columns, so the one -evaluation of is reused across all copies.
Hence the -evaluation count stays
with the same
and the same (the SIS
column width is unchanged because A, B, D are the same matrices). The only
thing the verifier must do differently is fold the fold copies into
the column weight before the scan.
The fused per-entry computation
Same single scan as single-machine, with the A·G_fold·z_hat column weight
combined over the folds in advance:
where is the z-equality weight of matrix column
within machine 's z_hat^(j) segment (at offset ). The
matrix column is , and
There is no g_commit factor in this setup weight. The g_commit factor appears
in the separate opening row over the z_hat segment.
The D·e and B·t patterns (, ) are rebuilt for the
distributed e/t layout but keep their single-machine size — because those
segments are partitioned, not replicated, every matrix column still maps to
exactly one witness column.
# Column patterns (precomputed once, NOT per row):
# W_col[c] : matrix col c -> distributed e-layout eq weight (size unchanged)
# T_col[g][c] : matrix col c -> distributed t-layout eq weight (size unchanged)
# Z_comb[c] = sum_{j in 0..M} Z_col_machine(j, c) (build O(M * A_cols))
acc = 0
for r in 0..r_max: # r_max = max(n_d, n_b, n_A) (UNCHANGED)
for c in 0..n_cols: # SIS columns scanned once (UNCHANGED)
r_eval = eval_ring_at_pows_fast(matrix[r][c], alpha) # the ONE O(D) alpha-eval — UNCHANGED count
setup_index_weight = d_w[r] * W_col[c] # D·e (partitioned, single-size)
+ sum_g b_w[g][r] * T_col[g][c] # B·t (partitioned, single-size)
+ a_w[r] * Z_comb[c] # A·G_fold·z_hat
acc += r_eval * setup_index_weight
The hot per-row loop is byte-for-byte the single-machine loop — only the
precomputed weight vector changed (Z_comb instead of Z_col).
The three column patterns
W_col[c](D · e_hat). Decode to(dig, blk_g, claim)as single-machine, then translate to the distributede_hataddress: the machine is the uniquemacwhose exact range satisfies , andblock_local = blk_g - s_mac. A precomputed block-to-machine map or a search over the public boundaries provides this translation. The equal-partition fast path reduces it to division and remainder. The column then lands in machinemac's piece. The total column count is unchanged.T_col[g][c](B · t_hat). The same with the extraa_rowaxis and per-group sparsity, against the distributedt_hatlayout; reuseseq_high_t.Z_comb[c](A · G_fold · z_hat). For eachAcolumn , sum over machines: . Each is theG_foldweighted equality sum over thedfaxis of machine 'sz_hatsegment. Build cost is ; in the non-power-of-twonum_positions_per_blockcase it is built densely per machine, as there.
Two coordinate systems (plus the machine axis)
matrix_evaluation reconciles M-layout (block innermost, defines the MLE)
with D-physical layout (digit innermost, the prover's commit order) by walking
in D-physical order and baking the M-layout translation into the column
patterns. The distributed layout adds one public range lookup to that
translation: blk_g = s_mac + block_local. The machine index is not generally
a high-bit slice of the block coordinate. The column-pattern builds absorb it; the
hot per-row loop never sees layouts or machines — it is still a dot product of
-evaluated entries against a precomputed weight vector.
Cost
| step | cost | done once per |
|---|---|---|
eq_high_e, eq_high_t, eq_high_z tables | verifier | |
W_col, T_col builds | verifier | |
Z_comb build | verifier | |
| -evaluations | ring ops | per row |
| per-row inner product | per row | |
| dominant | -evaluations — UNCHANGED | total |
The bottom row is the whole point: the -evaluations — the
verifier's true bottleneck — are performed exactly once per shared-matrix entry
and amortized across D·e_hat, B·t_hat, and all copies of
A·G_fold·z_hat. The only -dependent additions are the
combined-weight build and the
scaling of the cheap high tables — both far below the
-evaluation floor.
Cost summary: component by component
Putting the components side by side against the single-machine verifier
(, width of A = the z ambient size):
| component | single-machine | distributed (verifier total over all ) | delta |
|---|---|---|---|
e_hat consistency | heavy term unchanged; light | ||
t_hat consistency | heavy term unchanged; light | ||
z_hat tensor (replicated) | cheap term (no tiling) | ||
D·e_hat, B·t_hat setup scan | -evals over full , | identical | none |
A·G_fold·z_hat setup scan (dominant) | -evals | -evals | none |
| combined column-weight build | — | field ops | additive, cheap |
r_tail rows | one quotient | one summed quotient | none |
The distributed column is the verifier's total work (it is one entity that
sums over all machines), not the per-machine work. For the
partitioned e_hat/t_hat block scan the per-machine cost is , but the
pieces tile the same blocks, so the total is
. This remains true for uneven and empty ranges. The
replicated z_hat is the opposite: each of the
copies carries the full num_positions_per_block, the pieces duplicate rather than
tile, so the survives in .
The dominant row — the shared-matrix -evaluation scan — is
unchanged, because A/B/D are shared and seed-regenerated, and the
fold copies enter only through the additively combined,
-free . Every -dependent term is
field-arithmetic bookkeeping bounded by ,
negligible whenever (e.g. ,
leaves headroom for hundreds of machines).
The one additive cost: a few sum-check rounds
Because z_hat is replicated times, the next-level witness grows, so
its variable count rises by at most (less when t_hat
dominates the width, as is typical). The verifier therefore reads up to extra
sum-check round polynomials — a handful of field operations and a few hundred
proof bytes each. This is additive, logarithmic in the machine count, and dwarfed
by the unchanged -evaluation scan. Challenges, the batched target
(computed from the summed public right-hand side), the recursive
commitment, and the matrix-evaluation bottleneck are all flat in .
This is the precise sense in which the distributed-relation verifier has equivalent performance to today's verifier: identical in its dominant term, with overhead that is logarithmic in the machine count plus a negligible field-arithmetic pre-pass.
Partition shape and exact contraction
The combined equal-width tensor requires an equal block window
to be a power of two, so that block_local
occupies a contiguous low-bit window and the two-bucket carry split is defined
(the same condition num_positions_per_block must satisfy in the z-tensor Case 1). This holds
iff divides exact live and is a power of two.
At a root level, where , a choice
satisfies this automatically. A recursive level can
have and must not substitute merely to
recover equal chunks.
For uneven partitions, including , empty pieces are skipped and every nonempty piece keeps its exact . Short pieces use prepared affine block weights. Long pieces use the paired recurrence. Consecutive units with matching geometry are divided into power-of-two segments, and an irregular unit remains separate. The combined block work still covers each of the live blocks exactly once. A power-of-two machine count never permits the verifier to substitute a padded block domain for exact live .
Relationship to setup contribution modes
The dominant cost analyzed above is the shared SIS-matrix evaluation
scan. A schedule may check this setup contribution directly in Stage 2 or use
the deferred Stage 3 setup product described in
Setup contribution and Stage 3. The two choices use
the same SetupContributionPlan. The distributed construction does not change
that interface because both modes evaluate the same shared matrix and the same
exact chunk weights.
Verifier no-panic obligations
The distributed layout adds public structure the verifier must validate at the
boundary, consistent with the verifier no-panic contract.
The machine count and the block partition come from
the public schedule/layout, not from prover-controlled proof bytes, so the segment
offsets and the loop bounds are fixed before any proof
data is read. The verifier must reject a layout whose replicated
z_hat copies do not fit the validated next-level witness capacity, and confirm
the partition is the canonical contiguous one (so each is a well-defined
restriction of the global and the offsets are exact). After those boundary
checks the hot path above performs no -dependent allocation or
indexing that has not already been bounded; malformed input is rejected with
AkitaError / SerializationError, never by panicking.
Implementation map
crates/akita-params/src/witness.rsowns physical chunk, group, and segment addresses.crates/akita-params/src/witness/chunk_partition.rsowns the exact dyadic block ranges.crates/akita-types/src/setup_contribution/prepares the shared A, B, and D setup contribution.crates/akita-verifier/src/relation/evaluation.rscombines structured, setup, quotient, and compression contributions.crates/akita-verifier/src/relation/evaluation_trace.rsevaluates the opening trace over the same exact chunks.crates/akita-algebra/src/offset_eq/tensor_pair/owns the paired equality contraction and its dense test oracle.
Terminal verification
The final fold ends the chain of recursive openings. Its input is the preceding fold's witness-opening claim and a binding to that witness's inner A images. The prover sends a small folded response and the verifier checks the remaining relations directly.
The terminal reveals that response, the ring opening partials, and the inner images. It does not send the complete original application table. These are still witness-derived values, so this path provides no zero-knowledge guarantee.
The terminal input and response
Start with one polynomial in one source group, one response chunk, and a base-field opening over . Block has digit vector , with positions and inner digits . The public inner matrix is , where is the number of positions and the inner digit count. Its images are
The predecessor binds the canonical coefficients of all before its ring-switch and sumcheck challenges. The terminal response must contain exactly those bytes. Thus the prover cannot choose a new collection of inner images after seeing the opening point handed to the terminal.
Let be the position weights derived from that opening point, and the inner digit recomposition weights. The honest prover computes one ring partial per block,
and binds the partials before sampling the terminal sparse challenges . Its folded response is
The terminal response contains , the , and the . For live blocks, there are opening rings, inner-image rings, and response rings, all with coefficients. The schedule fixes these counts, including the convention for a partial final block.
The response uses recomposed ring values for and . There is no need to commit their digits through another B or D matrix, because the verifier reads them here.
The two ring checks
The terminal physical relation contains
consistency | A
The consistency check is
Substituting (2) and (3) shows why it holds for an honest response. Both sides are the same weighted sum of source digits. The A check is
For two blocks, the right side is . By (1), it equals , which is the left side by (3). The same response appears in both checks. Checking only (4) would leave its connection to the inner commitment unverified; checking only (5) would leave the opening partials unverified.
The verifier checks (4) and (5) in the native ring. There is no outer commitment value, B block, D block, polynomial-modulus quotient sumcheck, or Stage 1, Stage 2, or Stage 3 at this level.
Recover the scalar opening
The ring checks connect the response to the opening partials, but they have not yet compared those partials with the incoming scalar claim. Let be the opening point's block weights and its coefficient weights. These weights come from the query. They are different from the random fold challenges .
Writing for coefficient of , the remaining base-field check is
For a two-block example, first compute the coefficient pairings and . The verifier checks . This is the original table evaluation regrouped by block, as derived in field to ring reduction.
For openings over a proper extension , the terminal first replays extension-opening reduction. It obtains a transformed opening point, a terminal claim , and a known factor . The direct trace check then has the form
Here recovers the extension-valued coefficient pairing from the canonical subfield representation at the transformed point. It is the extension version of the inner sum in (6). Position multiplication in (4) uses the corresponding canonical ring multipliers.
The verifier computes these pairings in compact subfield coordinates. The inverse subfield map checks the complete canonical image, so malformed coordinates cannot be silently projected into a valid value. The preparation also supports the scheduled opening basis.
Extension-opening reduction has its own sumcheck. Therefore, eliminating the terminal's ring-switch and range sumchecks does not mean that every terminal proof is entirely sumcheck-free.
Response bounds and canonical decoding
Equations (4) and (5) are linear. Their binding argument also needs the response to be short. The schedule selects one of two mutually exclusive admission routes:
- A Linf route carries a coefficient cap . The verifier checks integer representatives with .
- An L2 route carries no independent Linf cap. After checking the signed 16 bit representation, canonical Golomb Rice encoding, and scheduled payload budget, the verifier checks the exact integer square sum
The right side is the schedule's squared-norm cap. This sum is not computed modulo the base field.
Response coefficients use the schedule-selected Golomb Rice encoding. The
decoder checks the exact coordinate count, a bounded maximum quotient,
canonical zero padding in the final byte, and the absence of trailing bytes.
The maximum quotient is derived from on a Linf route and from the
signed 16 bit wire bound on an L2 route. Both routes enforce the scheduled
payload budget and reject values outside [-32768,32767] before ring
arithmetic. The signed 16 bit representation is not an independent
schedule-selected Linf security cap on an L2 route.
The prover may search over the bounded fold-response nonces to find a response that satisfies these bounds. The verifier reconstructs the selected challenge and checks the bounds itself. It does not trust the prover's acceptance decision.
Replay order
The verifier performs the terminal handoff in this order:
- Check that the scheduled terminal geometry matches the remaining witness and that there is no deferred setup-prefix opening.
- Absorb the incoming inner-image binding and check that the response's coefficients match it exactly.
- Prepare the incoming point and claim. Replay extension-opening reduction when required.
- Absorb the , consume the terminal fold-response nonce, and derive the sparse . The L2 route also uses its scheduled challenge admission rule.
- Absorb the remaining response bytes, decode , and check its bounds.
- Check the ring relations and the scalar opening.
The predecessor's binding fixes before the terminal query is known, and step 4 fixes before is known. Both ordering constraints matter to the reduction. Once these direct checks pass, there is no further witness-opening claim.
Sparse products and the A matrix
To evaluate the sums involving , the verifier uses checked negacyclic shifts. A challenge monomial shifts coefficients and changes the sign of coefficients that wrap past . It does not require a dense quadratic ring product.
Challenge coefficients 1, -1, 2, and -2 use addition,
subtraction, and doubling. Other admitted coefficients use exact field
scaling. These sparse products multiply the opening partials and inner images
on the left of (4) and right of (5).
The A relation multiplies the decoded response by the prepared public matrix. The schedule audit selects an exact CRT and NTT capability before proof replay. It uses the base prime profile when the signed accumulation bound fits and adds the signed 16 bit tail only when required. A schedule whose bound exceeds every supported exact profile is invalid.
Prepared matrix views are derived from the coefficient setup and are never serialized. These execution choices compute the same relation (5).
No-panic boundary and code map
The verifier validates payload lengths, ring dimensions, coordinate counts,
sparse support, NTT capability, and matrix ranges before the hot kernels index
prepared state. Malformed terminal bytes return AkitaError or
SerializationError.
crates/akita-verifier/src/fold/terminal.rschecks the predecessor binding and replays the terminal transcript.crates/akita-verifier/src/terminal/direct.rschecks the decoded response norm, ring relations, and opening trace.crates/akita-verifier/src/terminal/ntt.rsevaluates the exact A product.crates/akita-params/src/golomb_rice.rsimplements the codec and its canonical-decoding tests.crates/akita-params/src/layout/tail_segments.rsdefines the response layout and transcript segments, andcrates/akita-types/src/proof/tail_segments.rsdefines the wire response.crates/akita-types/src/field_reduction.rsimplements subfield recovery.crates/akita-pcs/tests/transcript_hardening.rssupplies end-to-end regression coverage for terminal binding and proof tampering.
Security model
One canonical security narrative: the hardness assumption, how Ajtai ranks connect to security bits, the weak-binding fold price, and the current SIS table model. Keep the marketing claim separate from audited reality. See Reviewing and auditing Akita.
SIS / MSIS and Ajtai sizing
Production Ajtai key sizing uses generated Module-SIS width tables. The
generator certifies scalar cutoffs (B, n) -> max m under
Quantum128BitADPS16, and the checked-in runtime artifact stores the
Module-SIS projection:
(sis_security_policy, modulus_profile, d, coeff_linf_bound)
-> max secure ring widths by module rank
where width[r - 1] = cutoff_m(B, n = r * d) / d.
The shipped policy is Quantum128BitADPS16. It accepts a row only when the
complete ADPS16 quantum certificate reports a finite score or a classified
above-target lower bound of at least 128 bits. The decision threshold is an
explicit estimator configuration value supplied by the policy profile. The
beta search checks values from 40 through the capped Euclidean baseline and
stops once the monotone ADPS16 lower bound exceeds the best complete candidate.
It also returns a classified above-target result once both the best visited
attack and the lower bound for all unvisited beta values exceed 128 bits. For
B > 1, the global infinity estimate includes the Euclidean baseline
explicitly because L2 <= B implies L-infinity <= B; the baseline is
therefore an attack, not only a search cap. The diagnostic compression cells
with B = 1 are the production instance of the B <= 1 edge case, where this
model has no defined Euclidean-dimension optimization. They do not substitute
another bound: they omit that attack and sweep through the estimator's full
supported beta range. For each visited beta,
the optimizer exhausts every valid effective dimension before the LGSA profile
stabilizes, checks both endpoints of the stable unit-vector tail, and checks
both sides of any probability-regime transition inside that tail. The full
valid tall-lattice domain is 0 <= zeta < d - n. Fixed and exhaustive estimates
reject an effective dimension d - zeta <= n instead of pricing a non-tall
q-ary embedding. Width generation starts at the first tall ring width
width = rank + 1. Narrower widths inherit a cutoff only when that tall
instance is certified; if it already fails, the row emits cutoff zero and
runtime must choose a higher rank. A lookup for an unsupported policy, exact
modulus profile, role, or scalar cell fails closed.
The checked-in policy table may use local-minimum only to discover a candidate
boundary. Every emitted boundary and its immediate rejected successor are
certified under the proven-pruned beta and zeta domain. Parallel generation
parallelizes independent rows and does not change the certificate domain or
output ordering.
The infinity estimator evaluates Gaussian probabilities in log space, using the complementary error-function tail when the coordinate probability is close to one. Numerical allowances are applied toward greater attack success before combining coordinates, so rounding uncertainty favors a cheaper attack. Independent high-precision power-series fixtures check the probability calculation and integer repetition thresholds. These checks cover numerical regressions; they do not certify all floating-point lattice simulation steps.
The estimator hardening described above changes the acceptance model. The
checked-in SIS table retains the unversioned Quantum128BitADPS16 policy ID
and wire tag 1; evaluator revision akita-infinity-width-v4, the regenerated
table digest, and dependent catalog identities bind the corrected semantics.
The q32 Inner/A profile guard stops at 2^28 - 1; q64 uses 2^41 - 1; q128
uses 2^44 - 1. Within those guards, the audited A cells are the exact
one-response protocol collisions 4 * ||c||_1 * (2^t - 1) for reachable
opening-basis/digit-depth products t <= 33 and dimension-compatible challenge
families. A raw collision target selects the smallest covering audited cell for
the same profile and dimension; it does not jump to a generic power-of-two
bucket. B and D retain their exact gadget-anchor rounding.
CSV table-generation artifacts include the certified accepted and rejected successor witnesses, cutoff kind, cap provenance, and role provenance. These are audit inputs, not verifier-visible state. The shared table digest commits to the compact runtime table and its policy audit files together.
The planner has two production tables for the committed A role. The default
table uses a coefficient L∞ bound. A separate Euclidean table is available
only when the selected fold proves a complete physical squared L2 norm. Both
tables use the 128 bit quantum ADPS16 policy and have separate digests.
For the Euclidean table, the scalar SIS dimensions are n = rank * D and
m = width * D. The length bound is the square root of the complete collision
norm. The complete norm already includes every scalar coordinate, so the
planner does not multiply it by the matrix width again.
Inspect the modeled cost of generated schedules
The generated tables establish that each scheduled SIS instance meets the policy threshold. Maintainers can also run the estimator directly at every matrix coordinate in an expanded schedule. The report includes A, B, shared D, terminal A, precommitted and setup-prefix groups, and both maps in each compressed payload chain.
Run the summary for every checked-in catalog row:
cargo run --release -p akita-planner \
--features catalog-security \
--example catalog_security -- --check
The command prints one tab-separated row per schedule. --check returns an
error if a row falls below the target named by its SIS policy. Add --details
to print the expanded schedule and every SIS occurrence. Restrict the report
with a family name, --final-group NUM_VARSxNUM_POLYNOMIALS, or the exact
--row-digest HEX identity printed by the summary.
These numbers are derived diagnostics. They are not fields of the generated
schedule, schedule digest, proof, or verifier configuration, and the repository
does not track a perpetually regenerated report. A security- or schedule-review
PR may retain a head-pinned TSV under specs/evidence/, but that snapshot is
review evidence rather than runtime authority.
The reported value is the minimum scalarized SIS attack cost under the policy's ADPS16 quantum/LGSA model. It is not an unqualified concrete-security claim: the scalar estimator does not price attacks that exploit ring or module structure, CRT splitting, subfield projection, or role-specific matrix structure.
The production lookup is table-only. Verifier-reachable code must reject a
missing table row or unsupported floor with AkitaError; it must not run the
estimator at verification time.
Quantum policy
The production rule is the ADPS16 quantum LGSA model with a 128-bit target. It is an attack-cost model, not a physical resource estimate or an unqualified post-quantum security proof.
The conventional 0.2650 * beta quantum Core-SVP cost is deliberate. Akita
previously evaluated the newer idealized BCSS23 0.2563 * beta sieve as an
independently optimized diagnostic over 6,240 generated rows. Its reusable
quantum walks assume exponential sieve storage and writable coherent QRAQM;
zero accepted ADPS16 rows fell below the corresponding 124-bit review line.
The idealized model therefore remains documented sensitivity evidence rather
than a production constraint.
LGSA is likewise an explicit attacker strategy: rerandomize the q-ary basis so BKZ forgets its canonical q-vectors. On representative widened q64 and q128 rows, LGSA is no more expensive than ordinary GSA and is cheaper than the determinant-preserving Chen-Nguyen profile simulations. The optional symmetric ZGSA compatibility path caps its paired smoothing steps at the smaller of the q-vector and identity-vector zones, preserving the lattice determinant even when q-vectors are the majority.
Infinity-norm probabilities are priced on the coordinates that remain after
the attacker's zeta projection. In particular, the small-box condition uses
sqrt(d - zeta) * B <= q. Using the original dimension can select the wrong
probability formula and overstate security; this active-dimension rule is
regression tested, and integer production bounds use an exact boundary
comparison. Requests for the unimplemented high-precision backend fail closed.
The complete decision, assumptions, claim language, certificates, and
implementation acceptance criteria live in
specs/sis-quantum128-scalar-n-table.md.
Implementation map
crates/akita-params/src/sis/mod.rs,ajtai_key.rs,l2_table.rs,physical_l2.rs,generated_sis_table/, andnorm_bound.rs.docs/security-posture.md,specs/sis-quantum128-scalar-n-table.md.crates/akita-params/src/sis/generated_sis_table/policy_audit.csv(canonical production table certificate).
Norm bounds and weak binding
Every committed level records one A role security route. The coefficient
L∞ route is always available. Every production profile also enables the typed
L2 response model from level 3 onward. The root and early folds do not use the
L2 route. A clear terminal response may use the route because the verifier
computes its complete integer norm directly.
Let kappa_1 be the maximum physical coefficient L1 norm of the fold
challenge. Let gamma be the bound used for challenge multiplication. This is
either kappa_1, or a verifier enforced operator norm threshold. Let Z_inf
be the accepted physical coefficient bound on the response, and let S be the
accepted squared norm of the complete physical response. The two collision
bounds are
C_inf = 8 * kappa_1 * Z_inf
C_2_sq = 64 * gamma^2 * S.
These formulas use the physical ring coefficients that enter the A role Module SIS kernel. The small field extension embedding has already produced those coefficients. Applying the Hachi logical to physical conversion at this point would count that conversion twice.
For a chunked response, the A rows do not bind each chunk independently. They bind the effective response
z_sum = z^(0) + ... + z^(C-1).
Stage 1 nevertheless range-checks every chunk in the same balanced
base-2^ell digit interval. If each chunk uses delta digits, the exact
difference between two accepted values in one chunk has diameter
2^(ell * delta) - 1. Differences add across the C chunks, so the exact
coefficient collision target used by the A role is
C_inf_chunked = 4 * kappa_1 * C * (2^(ell * delta) - 1).
This is the chunk-aware form of the same weak-binding calculation. Pricing a
chunked row as though C = 1 would certify only one accepted response even
though the shared relation admits their sum. Akita therefore treats the
response-chunk count as a schedule parameter, re-derives this target during
planner replay and verifier admission, and rejects a row whose stored A bound
is smaller. All chunks use the same digit basis, digit depth, and full ambient
Z width. Their honest norms and their assigned E/T block counts may differ.
The selective L2 route remains restricted to one response chunk.
The checked-in infinity table does not multiply its coverage by every supported response-chunk count. Instead, a chunked raw target reuses the smallest audited A cell that covers it. This is usually tight, but two- and four-chunk schedules can inherit a conservative collision bound when their target lies in a gap between existing cells. That choice can make the resulting SIS rank larger than a table search specialized to that exact chunk geometry. We accept this possible loss to keep the certified table small. Maintainers add a sparse refinement cell only when catalog measurements show a material schedule improvement; lookup fails closed when no existing cell covers the target. The current table adds eight fp128 refinement cells for measured two- and four-chunk operating points, contributing 160 certified rank rows. It adds no eight-chunk coverage axis or dedicated eight-chunk cell.
An L∞ schedule carries no norm proof. An L2 schedule binds its cap and
integer proof shape into the schedule descriptor. The verifier proves the norm
of the same physical Z coefficients used by the security calculation and then
checks the public cap. The existing digit range proof remains mandatory. For a
clear terminal response, the verifier decodes every coefficient, computes the
integer square sum, and checks the same cap without a sumcheck.
The D64 and D128 L2 routes use transcript replayed operator norm rejection.
D64 uses the (31, 11) signed shell and runtime threshold 18. D128 uses the
production (31, 0) shell and runtime threshold 13. The fixed point checker
uses 48 fractional bits and accepts only a certified subset below the stated
mathematical threshold. Its rounding margins are 600 units for D64 and 351
units for D128. Exact support certificates show that each accepted family
retains at least 128 bits.
The response model is an honest prover model, not a security assumption. An
eligible source carries a modeled squared norm through the typed Z, E, T, R,
compression, and extension packing operations. The planner rounds that source
estimate upward, adds a 3 percent model envelope, and permits a response up to
40/39 times the resulting conditional mean. Markov's inequality gives a
distribution-free grinding bound if the 3 percent envelope covers the source
model error. The planner freezes the resulting cap into the schedule. The
verifier enforces that exact cap. A model error can make proving fail more
often, but it cannot make the verifier accept a response above the cap.
Alignment coordinates
Witness alignment gaps are physical committed coordinates outside the semantic Z/E/T, quotient, and compression spans. Stage 1 range-checks these coordinates with the ordinary balanced digit range. They have no direct relation equations and no negative-binary constraint. The canonical prover initializes them to zero, but verification does not require zero.
The successor commitment consumes the complete physical witness, including alignment coordinates. Its block geometry and matrix input widths cover this source; SIS rank admission uses those widths and the accepted digit or response bounds, without assuming the filler is zero. The current fold's A-role response norm covers its semantic Z ranges, so changing its alignment coordinates does not directly change that norm. Once the successor consumes the witness, filler can change its response. That response must satisfy the successor's scheduled coefficient bound or its proved physical squared L2 cap, including the direct terminal norm check when applicable.
Zero filler contributes no energy to the honest source model. This convention can be used to select a cap, but the security calculation uses the cap enforced by verification. Nonzero filler need not produce a response below that cap: range membership alone does not guarantee acceptance of every later fold.
The accepted committed-source space
A committed level stores num_digits_inner balanced base-2^log_basis_inner
digits per source coefficient. CommittedSourceContract::accepted_bounds
computes the accepted centered interval for a balanced signed digit source. It
intersects what those digits can represent with the declared
DecompositionParams::log_commit_bound that the schedule was priced for.
The source class and numeric bound are independent. The class selects either the
unit one-hot structural contract or the balanced signed digit contract. The bound
selects the digit depth for either class. A balanced signed digit source may use
any valid bound, including 1 and the field width. A unit one-hot source remains
unit one-hot at any valid bound.
The intersection matters because the depth rounds up, so the representable envelope is strictly wider than the declaration — by 256x at some shipped geometries. The declaration is the binding side, because the planner prices a bounded source's final digit plane at only the range its bound leaves.
A smaller bound is a smaller accepted witness space, not a weaker commitment. The
A-role collision bounds above are computed from the same digit envelope the
verifier admits, so a bounded family is priced for exactly what it accepts. The
unit one-hot class has a separate structural admission check. The declared bound
is inside DecompositionParams, which is hashed into the external artifact's
policy identity and serialized into the instance descriptor, so a proof cannot be
replayed against a family with a different bound.
The obligation the smaller space creates is on the producer, and it has two
halves. Committing above the representable envelope would bind a truncation,
because the decomposition keeps only the scheduled digits. Committing above the
declared bound would instead inflate the level-1 witness past the L2 response caps
frozen into the recursion suffix, because those caps were priced from the
declaration. commit rejects both. See
Bounded committed sources.
The fold nonce does not incur a fixed 12-bit soundness loss. Every nonce trial is another random-oracle query, so the Fiat-Shamir reduction charges it through the adversary's total query budget. See Polynomial commitments and binding.
Reduced ring-relation soundness
Quotient lifting and reduced evaluation enforce the same native-ring relations through different witness geometries. For one physical row of native dimension , reduced evaluation forms the residual
The protocol checks at the existing ring-switch challenge . If the row relation is false, is a nonzero polynomial of degree less than , so random evaluation over the extension challenge field has the usual Schwartz--Zippel bound. The existing challenge batches the canonically ordered physical rows after each has been reduced in its own native ring dimension.
The schedule, witness layout, relation mode, public statement, commitments,
and outgoing witness are bound before is sampled. Consequently the
prover cannot choose the relation realization or its witness after seeing the
evaluation point. RingRelationMode is part of the instance descriptor and
effective schedule digest, not a proof field.
Reduced evaluation never divides by . An evaluation point that is
a root of the cyclotomic modulus therefore needs no special rejection: the
signed-wrap residue recurrence and terminal verifier kernel remain defined.
Removing quotient spans also does not change the A-role SIS binding argument,
the digit-range proof, or the scheduled L∞/L2 response cap. It only removes
coordinates that existed to witness polynomial divisibility.
Subring coefficient packing
For the coefficient layout, the three ring domains, and the exact reason the partial evaluation is shorter, first read Subring coefficient packing. This section focuses on transcript binding and soundness.
Before sampling a packing challenge, the prover binds every coordinate of the
partial opening through the D payload or its compressed H payload. The
transcript also binds the method, challenge subring dimension, challenge
family, group order, claim count, and block count. After challenge folding, the
prover binds Q_pack and the next witness before sampling alpha.
Both opening methods squeeze one dedicated 32-byte root per commitment group.
They then derive coordinate (claim, block) from a fresh SHAKE256 stream whose
input is exactly that root followed by the claim-major coordinate index as a
little-endian u64. The fixed widths make this encoding unambiguous. The
coordinate streams do not mutate the live transcript. Sequential and parallel
samplers therefore return the same ordered vector, and one coordinate can be
forked without changing any other coordinate.
The production primes satisfy the fixed LS18 congruence and shortness condition used for unit pairwise challenge differences. This fact belongs to the field and challenge security review. It is not planner metadata and does not require a per-schedule certificate.
For a coordinatewise fork, fix the transcript prefix, group root, shared fold-response nonce, and all coordinate-oracle answers except one. If both forks yield accepting transcripts, their challenge difference is zero outside that coordinate. The production LS18 condition makes every nonzero sparse-challenge difference a unit, so subtracting the accepted relations algebraically isolates that opening. A binary CWSS extractor would need a central accepting vector and one such accepting fork for every claim-major coordinate. Complete accepting descendant trees authenticate the later relations and response bounds. The indexed matching-input game bounds failure to obtain these forks by charging every queried or verifier-completed coordinate address; see the fold argument.
The packed consistency equation still gives one polynomial identity in E[Y].
After including the (Y^s + 1)Q_pack term, its degree is at most 2s-1, so the
conditional polynomial-check error is (2s-1)/|E|. This term must be composed
with the CWSS, random-oracle, sum-check, collision, and MSIS terms. The active
subring coefficient packing design record
gives the algebraic relation and its separate field-check loss. The fold
contribution is accounted by the indexed-address theorem above.
The challenge response identity is exact when the accepted challenge has scalar covariance. The fixed point operator norm filter is not assumed to have perfect symmetry. Five million sampled orbit comparisons at D64 and D128 had no acceptance mismatches. Full orbit tests also had no mixed outcomes. The measured covariance defect was about 0.07 percent, and explicit orbit randomization did not improve it. The protocol therefore keeps the existing challenge sampler.
Implementation map
crates/akita-params/src/sis/norm_bound.rsowns the two physical collision formulas.crates/akita-types/src/proof/relation_range_image.rsowns the physical response map.crates/akita-cpu-backend/src/opaque/sumcheck/physical_l2_norm.rsandcrates/akita-verifier/src/stages/physical_l2_norm.rsown proof and replay.specs/archive/2026-Q3/weak-binding-norm-fix.mdrecords the earlier fold reprice.specs/fold-linf-rejection.md(fold digit-count tightening).specs/selective-l2-fold-security-sizing.md(implemented physical norm correction and optional L2 route).crates/akita-params/src/config.rs(DecompositionParams::log_commit_bound) andcrates/akita-cpu-backend/src/commitment/api.rs(ensure_sources_fit_accepted_interval) own the declared committed-source bound and the producer-side range check.
Prover Optimizations
Akita keeps protocol decisions separate from compute decisions. The protocol chooses the commitment layout, transcript order, and proof shape. A compute backend receives a validated source view and performs one named operation. This split lets the CPU implementation change storage and traversal without changing proof bytes or exposing CPU plans as public API.
The current CPU design has three important rules:
- The source owns only its logical witness.
- Derived data belongs to the operation that uses it.
- Prepared setup state owns only data that is useful across operations.
These rules are most visible in one hot commitment and large ring switch operations.
One hot source geometry
A one hot polynomial stores an optional hot index i_j for each chunk j.
The chunk arity is K. A present index identifies the global nonzero field
coordinate
g_j = j K + i_j.
For ring dimension D, this coordinate maps to a ring and coefficient by
ring_j = floor(g_j / D),
coeff_j = g_j mod D.
If one commitment block contains P ring positions, the same coordinate maps
to
block_j = floor(ring_j / P),
position_j = ring_j mod P.
This is the only coordinate rule. Single chunk and multi chunk layouts do not
need different stored block types. OneHotPoly stores the indices and scalar
shape data. Its D-free commitment representation carries those semantics into
request compilation; OneHotView remains the typed opening view.
One group commitment operation
The protocol always commits a group. A singleton is a group with one source.
Each source first advertises its representations without materializing them;
request compilation intersects those choices with the registered operation's
capabilities. CommitmentExecutor then materializes only the selected path and
runs either independent inner/outer operations or one explicit fused operation.
Dense, one hot, and recursive witness sources implement the same D-free
CommitmentSource boundary without sharing a CPU representation. Commitment
state remains policy-selected: a portable policy exports the existing hint,
while a resident policy keeps backend state in process.
The CPU one hot path runs this flow:
validated OneHotRepresentation values
|
v
derive the active block interval
|
v
materialize one operation tile as flat sparse entries
|
v
run the selected matrix sweep
|
v
place rows in source order and drop the tile
The driver partitions the concatenated block range once. Each tile builds only the entries that overlap that tile. The output rows remain live because they are the result of the operation. The sparse entries and sweep scratch are dropped at tile completion.
This ownership also applies to opening and recursive-suffix tensor projection. Opening builds only the active challenge range. Batched opening keeps only the current polynomial and its current block tile. Suffix tensor projection consumes the recursive witness source directly. Cloning a one hot polynomial does not share mutable derived state.
Streaming suffix tensor inputs
When a recursive evaluation-trace fold needs extension-opening reduction, column partials consume the compact witness digits through a row iterator. Each digit is converted to a base-field value when read, and missing padded entries yield zero. This avoids allocating a complete padded base-field table. Packing also reads the compact source directly, but produces a full extension-field table. The reduction retains that packed table and its sumcheck state, so this input streaming does not give the whole prover constant memory usage.
The small-space EOR roadmap describes a separate, not-yet-implemented approach to reducing those retained tables.
The implementation and its comparison with a padded-table reference are in
crates/akita-cpu-backend/src/opaque/recursive/witness/tensor.rs.
Tiling and sweep selection
Tile size and arithmetic traversal solve different problems.
The tile size bounds temporary memory. The CPU kernel computes its scratch budget internally as the larger of a private 8 MiB batching target and the estimated minimum needed for one block. The target lets small blocks share a matrix pass; using only the minimum would force one block per tile. The estimate includes sparse entries, sweep indexes, wide accumulators, reduced rows, and small offset arrays. In simplified form,
tile = floor((budget - fixed scratch) / scratch per block).
The result is capped by the number of live blocks and by the packed local block index range. All size arithmetic is checked.
The sweep selects how a materialized tile reads the public matrix. The retained CPU choices are:
- Bucketed sweep. Entries are grouped by active matrix column, then every matrix row is scanned once.
- Merge sweep. Sorted block cursors are advanced while a bounded group of active columns is loaded once.
Both sweeps load a matrix entry a as NegacyclicShiftWindows: the canonical
16-bit lanes of [-a, a], so coefficient j of a * X^k is entry
D + j - k. When a ring holds several one-hot rows (K < D), one block adds
several shifts of the same entry. The windows read each shift as one
contiguous window and add up to eight windows per pass over the wide
destination, instead of updating the whole destination once per shift. The
kernel runs over the flat 16-bit and 32-bit lane slices that jolt-field
exposes, so each vector instruction widens and adds whole lanes rather than
shuffling per-coefficient lane groups. Each shift adds a value
below 2^16 to each signed 32-bit lane, so the field's commit accumulation
budget bounds the shifts between reductions. On x86-64 the kernel dispatches
at runtime to an AVX2 build of the same loop.
Both sweeps consume the same flat sparse entries and produce the same rows. The private selector uses total block count, active column count, and worker count. Correctness tests compare both retained sweeps with a direct arithmetic reference. A release benchmark measures the retained choices over the production region. The profile report records the selected sweep and tile so a route change is visible even when total runtime is noisy.
CPU resource limits
CpuBackend::with_ring_switch_cache_limit(expanded, max_cached_ring_switch_elements) sets the largest ring switch operation that
keeps a complete transformed matrix prefix. CpuBackend::new uses 2^21 ring
elements. A zero limit streams every ring switch operation that has a streamed
implementation. usize::MAX retains every supported operation.
Commitment scratch sizing and sweep selection are internal kernel decisions, as described above. Scratch is per worker and excludes the prover's other resident data, so automatic sizing does not impose a total memory limit.
These policies choose equivalent CPU execution paths. They do not change the proof schedule, transcript, setup bytes, proof bytes, or verifier behavior.
Wide accumulation
Commitment kernels accumulate several products before reducing to the base
field. The safe number of additions depends on the field and CRT profile.
F::MAX_COMMIT_ACCUMULATIONS is the single contract for this limit.
If a one-hot block contains more terms than the limit, both retained sweeps reduce the wide accumulator at the same cap and continue from zero. Ring shift helpers preserve negacyclic wrap. Tests reach the exact addition cap with maximal canonical limbs and cover wrapped shifts.
Compact digit range proving
Stage 1 proves the range protocol described in Sumcheck stages, but the prover does not begin by expanding every digit into a field-valued range-image table. It keeps the balanced digits in packed signed storage and exploits the involution
The two digits in each pair have the same range image:
The implementation therefore replaces a balanced digit by its small collision class
and recovers the range image as c(w)(c(w)+1). Padding uses class zero. A
CompactDigitSource stores the packed digits, the exact live-prefix geometry,
and, when a class-indexed stage needs them, compact indices for consecutive
ordered class pairs.
For bases 16, 32, and 64, the product substages compute their first two rounds from small tables indexed by these class pairs. After the first challenge, the prover either uses a quartet coefficient table or rescans factorized folded pairs to prepare the second-round polynomial. Only after the second challenge does it materialize the exact folded table, now one quarter of the original Boolean domain. The final range leaf uses the same class-indexed machinery; the basis-16 leaf has the dedicated two-round quartet path.
On the coefficient-bound route, the direct basis-4 and basis-8 leaves keep the
digits packed for four rounds. The first three rounds bind the position of an
entry inside an aligned octet of the flat table, so until the fourth round every
folded entry depends only on the classes of its octet's eight entries. Before the
first round the prover scans the packed digits once, reading each octet's class
directly from its packed bytes, and adds the fourth round's equality weight of
each live pair of adjacent octets to two tables indexed by octet class: one for
the pair's even octet and one for its odd octet. Each table has at most 2^16
entries. Blending the two tables with the fourth round's equality coordinate
gives the third round's weight of each octet class. The quad-class marginals of
that blend give a bivariate prefix that reconstructs the first two sumcheck
messages, and the third message is a sum over octet classes.
The fourth message pairs adjacent octets. Its linear sum, the weighted difference of the two range values across each pair, separates over the two octet classes, so it is a sum over octet classes of the range value times the difference of the two tables. The higher coefficients read, per octet class, the folded value and two Taylor factors of the range polynomial at that value. The equality weight multiplies the squared difference once, so a basis-8 pair costs one squaring, two multiplications, and three unreduced multiplications, and a basis-4 pair one squaring and one unreduced multiplication. The prover materializes the range image only after the fourth challenge, at one sixteenth of its original length, and computes the fifth message in the same pass. A Euclidean fold instead uses the class-indexed leaf described below because the norm term shares its rounds.
These are prover-only representations. The transcript contains the same stage claims and sumcheck polynomials defined by the protocol, and the verifier does not need to know which compact kernel produced them.
Physical Euclidean norm proving
When the schedule selects the Euclidean security route, the prover reconstructs
the complete physical response from its packed digits according to
PhysicalResponsePlan. This is an explicit materialization: the direct route
builds one centered-integer response table, while the small-field route builds
the signed limb tables needed for its Gram decomposition. The implementation
then converts these exact prefixes to field tables for sumcheck.
The prover does not run a separate sumcheck over those tables. It batches the physical norm identity into the final digit-range leaf and uses the same challenge vector:
- The direct route contributes the degree-two polynomial for
sum_x z(x)^2. - The limb-Gram route contributes selected degree-three products of signed limb pairs. Public block-and-pair subclaims are combined with a transcript challenge, and checked integer arithmetic reconstructs the complete squared norm outside the field.
The latter route is required when the whole squared norm need not fit below the base-field modulus. Each individual Gram subclaim has a unique centered lift, so the verifier can recover the integer norm without accepting a value that wrapped in the field.
At the final point, the proof exposes one virtual response evaluation for the direct route or one evaluation per limb for the Gram route. Stage 2 ties those values to the balanced digit planes of the committed response. The fused Stage 1 proof saves a second round sequence, but it does not pretend that the physical response tables are free: their materialization is part of the Euclidean prover's memory cost.
Relevant sources:
crates/akita-cpu-backend/src/sources/packed_digits/owns compact signed-digit storage.crates/akita-cpu-backend/src/opaque/sumcheck/digit_range/owns the direct and class-indexed range provers.crates/akita-cpu-backend/src/opaque/sumcheck/physical_l2_norm.rsfuses the physical norm with the final range leaf.crates/akita-params/src/sis/physical_l2.rsdefines the direct and limb-Gram plans and reconstructs the integer norm.
Prepared NTT state
The flat public matrix is stable setup data. A transformed matrix prefix is a
backend optimization. CpuPreparedSetup owns transformed prefixes keyed by
ring dimension, transform domain, and exact ring extent.
NttExecutionRequirements describes the matrix operations in one proof. It
does not decide which transformed prefixes remain resident. The routed backend
applies one retention rule during planning, prewarming, memory reporting, and
execution:
execution requirements
|
+--> retained operation: prewarm or build an exact cache slot
|
+--> streamed operation: transform one matrix chunk at a time
Large ring relation and quotient operations stream transformed chunks. Their complete transformed inputs never become prepared cache slots. Smaller reused operations retain exact prefixes across proofs.
The requirement record retains each operation's routing extent until the backend makes this decision. This prevents a large streamed operation from hiding a smaller cached operation on the same matrix route. Requests from one fused operation share one routing extent across transform domains. Only retained requests are max-joined into physical cache slots.
Shared prepared caches may remain available across proofs. Applications can
call backend.trim_caches() to release built shared-matrix transform slots.
On CPU, release removes built shared-matrix transform slots. Compression transforms remain resident. Active readers keep released slots alive through shared references. The reported byte count describes removed cache entries; their storage can remain allocated until those readers finish. A later request builds its exact extent instead of reusing a removed covering slot.
Trim when releasing the shared cache will not remove warm state needed by concurrent work. Trimming does not guarantee an immediate drop in process memory, and proof completion does not clear the shared cache. The setup runtime guide describes this application choice.
CpuPreparedSetup::shared_ntt_cache_bytes and
compression_ntt_cache_bytes report each namespace. ntt_cache_bytes returns
their checked sum. Planned requirement metrics describe only shared matrix
work because compression entries are created by compression operations.
Ring relation and quotient streaming
Cached and streamed ring switch execution use the same validated geometry. The private quotient plan owns:
- active digit and opening role lengths;
- checked matrix extents;
- centered digit bounds;
- CRT safe chunk ranges;
- cached and streamed input shape checks.
The field width dispatch chooses only the concrete CRT arithmetic profile.
It does not rebuild validation or chunk planning in separate q32, q64, and
q128 branches.
For a matrix with R rows and active width W, cached execution consumes a
validated transformed prefix of R W ring entries. Streamed execution covers
the same logical range in CRT safe chunks. Both modes return the same relation
or quotient rows. Differential tests exercise each field profile with a
distinct CRT capacity.
Copy and parallel range reductions
Owned fold output moves directly into the existing proof container through a consuming constructor. It does not copy between equivalent row layouts.
Exact prefix products use nonoverlapping parallel waves. Each wave reads a completed prefix and writes the next disjoint range. Dense differential tests cross the sequential boundary and every doubling boundary through the full supported domain.
Design boundary
CPU storage plans remain private. A new backend implements the source typed operation for its device and chooses its own storage, tiling, and scheduling. It must preserve source order, checked geometry, arithmetic limits, and the protocol output type. It must not absorb transcript state or expose a CPU row plan as public API.
See Compute Backends for backend ownership
and NTT lifecycle details. The full PR 375 design record is
specs/archive/2026-Q3/pr375-prover-streaming-and-onehot-unification.md.
Foundations
These chapters explain the mathematical and cryptographic ideas that the rest of the Book uses. They are written for readers who may know Rust but have not studied polynomial commitments, as well as for cryptographers who want to check how each abstract rule becomes code.
You do not need to finish every foundation before using Akita. An integrator can start with Usage and return here when a term or design choice needs more explanation. A contributor or reviewer should follow the paths below until every claim they are changing has a clear implementation and validation boundary.
Current depth: this landing page is complete. The rings, NTT and CRT, gadget decomposition, Module-SIS, multilinear sum-check, and equality-factored sum-check chapters are full implementation narratives. The commitment and binding chapter gives a current security overview. The extension-opening chapter gives a detailed protocol walkthrough with a numerical example; a complete soundness analysis remains out of scope.
What these foundations connect
Akita sits at the meeting point of four subjects:
- Tables and polynomials. A table with entries determines one multilinear polynomial in variables that agrees with the table at every input made of zeroes and ones. This gives the proof system an algebraic way to ask for one value without sending the full table.
- Fields and polynomial rings. A field is a number system with addition, subtraction, multiplication, and division by nonzero values. A ring keeps addition, subtraction, and multiplication but may not support every division. Akita's polynomial rings group many field values into one object for lattice commitment operations.
- Checks with derived challenges. Sumcheck turns one large polynomial identity into a sequence of smaller claims. A transcript is the ordered record of public inputs and proof messages. The Fiat Shamir transformation derives the verifier's challenges from that record, so the proof can be checked without a live conversation between prover and verifier.
- Lattice binding. Public matrices commit to short ring vectors. Module-SIS is the hardness assumption used to argue that a prover cannot open one commitment in incompatible ways.
The implementation adds a fifth concern: all of these objects must have exact sizes, layouts, encodings, and fast arithmetic paths. A mathematically correct description is not enough for an implementation audit. A reviewer must also check where parameters enter, where malformed input is rejected, and whether an optimized kernel computes the same result as its reference path.
A first path for new readers
If this is your first polynomial commitment scheme, use the following order. It starts with the object being proved and ends with the security claim.
- Read Multilinear extensions and sum-check to see how a table becomes a polynomial and how a large identity is reduced to one evaluation.
- Read Cyclotomic rings and extension fields to learn where Akita stores coefficients and why some evaluation points live in a larger field.
- Read Gadget decomposition to see how one large coefficient becomes a list of small signed digits. That chapter includes concrete examples and the path into the current code.
- Read Lattices and Module-SIS for the hard problem behind the commitment.
- Read Polynomial commitments and binding to connect setup, commitment, opening, verification, and the security assumption.
- Return to How it works and follow one Akita proof from configuration to terminal verification.
NTT, CRT, and fast ring arithmetic can wait until you want to understand performance or audit the arithmetic kernels. The specialized sumcheck and opening reduction chapters are easier after the general sumcheck chapter.
The chapter map
The order below matches the order in the Book sidebar. The status column describes the current documentation, not the maturity of the corresponding code.
| Chapter | The question it answers | Current depth |
|---|---|---|
| Cyclotomic rings and extension fields | What number systems does Akita use, and how does it move between coefficient and evaluation views? | Full introduction with examples, field roles, ring arithmetic, embeddings, norms, and an implementation review map. |
| NTT, CRT, and fast ring arithmetic | How does Akita multiply and transform ring elements efficiently across its supported prime sizes? | Current implementation narrative, including scalar, AVX2, and AVX 512 paths. |
| Gadget decomposition | How does Akita replace a coefficient with bounded signed digits, and how is the exact range enforced? | Full introduction with examples, formulas, layouts, code paths, and an audit checklist. |
| Field arithmetic | How are protocol field values represented, reduced, accumulated, and sampled? | Production field families, canonical arithmetic, exact sampling, extension operations, and accumulator bounds. |
| Lattices and Module-SIS | What hard problem supports binding, and why do short vectors and norm bounds matter? | Full introduction from integer lattices through commitment collisions, generated security tables, and verifier enforcement. |
| Multilinear extensions and sum-check | How does a table become a polynomial, and how can a verifier check a large sum with little work? | Full introduction with a complete two-round example, compressed messages, soundness, unequal-size batching, and an implementation review map. |
| Equality-factored sum-check | How does Akita exploit the structure of an equality polynomial while avoiding verifier inversions? | Full derivation of the smaller round message, scaled verifier update, split equality tables, scope, and review checks. |
| Extension-opening reduction | How does Akita open a base-field polynomial at an extension-field point? | Detailed protocol walkthrough with a numerical example and implementation references; multi-group execution is covered in the linked implementation page. A complete soundness analysis remains out of scope. |
| Polynomial commitments and binding | What do setup, commitment, opening, and verification promise, and how is incompatible opening tied to Module-SIS? | Current security overview with implementation anchors. More introductory examples can still be added. |
| Glossary and notation | What do recurring Akita names and symbols mean? | Current lookup reference for protocol terms, catalog rows, and notation. |
| Spec index | Which design records are live, implemented, or retained as history? | Current maintainer index. |
| References | Where can a reader find stable external background for the ideas used here? | Curated public references grouped by subject. |
Paths for different jobs
The same chapter can be read at different depths. Use the path that matches the decision you need to make.
Application integration
An application integrator needs the public contract before the internal proof. Start with Quickstart, then use these foundations to answer specific questions:
- multilinear extensions explain the required polynomial shape and opening points;
- fields and rings explain which value types belong to a configuration;
- polynomial commitments and binding explain what acceptance means;
- the zero knowledge roadmap explains what the current proof does not hide.
Protocol contribution
A contributor changing a proof stage should read the general foundation first, then the matching chapter under How it works. For example, a change to a sumcheck driver should be checked against both the generic sumcheck rules and the transcript order used by the proving and verification paths.
The important question is not only where a function is called. It is which protocol fact the function owns. One canonical function should enforce each size formula, range, transcript label, or acceptance rule.
Cryptographic review
A cryptographer can use the Foundations chapters to separate a general argument from an Akita parameter choice. For each claim, identify:
- the mathematical statement;
- the public parameters that instantiate it;
- the code that validates those parameters;
- the verifier code that relies on the statement;
- the tests that cover accepted and rejected cases.
The security model then connects these local checks to the complete knowledge and binding claims.
Implementation and performance audit
An implementation auditor should follow both the logical value and its physical representation. The same ring element may appear as coefficients, transformed values, packed lanes, or a flat field vector at different points in the code. The NTT and gadget chapters state where those changes happen and which scalar path can be used as a reference.
Pay special attention to dispatch by field and ring dimension, integer capacity before deferred reduction, canonical decoding, checked allocation sizes, and unsafe vector code. These are places where a correct formula can still become an incorrect implementation.
From concepts to crates
The main implementation owners are:
| Concept | Primary code owner |
|---|---|
| Prime fields, extension fields, packed values, and field kernels | external jolt-field |
| Cyclotomic rings, NTTs, modules, and gadget decomposition | akita-algebra |
| Generic sumcheck proof types and drivers | akita-sumcheck |
| Transcript construction and challenge sampling | akita-transcript and akita-challenges |
| SIS parameters, commitments, proof shapes, and schedules | akita-types |
| Concrete configuration policy | akita-config |
| Commitment and proof execution | akita-prover |
| Verifier replay and rejection | akita-verifier |
This table gives ownership, not a substitute for explanation. A completed chapter should define the concept first, show a small example, state the rule, and then identify the exact source and tests that enforce it.
What to remember
The Foundations section has two jobs. It should let a new reader understand the ideas without opening the source, and it should let a reviewer find the source without guessing what each function is meant to prove.
When a chapter is still short, treat it as a map rather than a complete lesson. When a chapter is complete, its prose should agree with current code, live specifications, generated data, and tests. Any disagreement is a defect to resolve, not a choice between equally valid descriptions.
Cyclotomic rings and extension fields
Akita uses three related kinds of number system. Each one has a different job.
- A prime field stores the coefficients supplied by an application.
- An extension field supplies large random challenges and evaluation points.
- A cyclotomic ring groups many field coefficients into one object for lattice commitments and fast polynomial arithmetic.
This chapter builds those objects from the ground up. It then explains how the current Rust types represent them.
Prime fields
Choose a prime number . The prime field contains the integers from through , with every operation reduced modulo .
For example, in ,
The first equality holds because and differ by . The second holds because is also congruent to modulo .
Every nonzero field element has a multiplicative inverse. This is what makes a field different from a general ring. Division by a nonzero element means multiplication by its inverse.
Akita ships configurations over three prime sizes:
| Family | Base field size | Evaluation field |
|---|---|---|
fp32 | About 32 bits | Degree 4 extension of the base field |
fp64 | About 64 bits | Degree 2 extension of the base field |
fp128 | About 128 bits | The base field itself |
The exact prime belongs to the configuration. For example, the current fp128 family uses . The field-arithmetic chapter explains how the production fields are stored, reduced, accumulated, and sampled.
Extension fields
An extension field adds new elements while keeping the original field as a subfield. If is a degree extension of , then has elements. Each element can be written with base field coordinates.
For a degree 2 extension, an element has the form
where and satisfies a fixed irreducible quadratic equation. The equation defines how powers of reduce during multiplication. A degree 4 element has four coordinates. Akita fixes the basis and coordinate order with the field type; it is not selected by a proof.
Akita uses extension fields because challenge size controls the probability that a false polynomial identity passes a random evaluation. A 32 bit base field is useful for fast arithmetic, but a single 32 bit challenge is too small for Akita's security target. A degree 4 extension gives a challenge field with about 128 bits. The fp64 family reaches the same size with a degree 2 extension. The fp128 family needs no extension.
The code records this relationship through ExtField<F>. Its
DEGREE constant gives . from_base_slice and to_base_vec convert
between an extension element and its canonical base field coordinates.
Coefficients and evaluation points have different roles
A polynomial can have coefficients in the base field and still be evaluated at a point in an extension field.
Suppose
has coefficients in . If belongs to an extension field , then also belongs to . The base values are embedded as constant elements of before the arithmetic is performed.
This is the common small field case in Akita. The committed table contains values in , while sum-check challenges and claimed evaluations live in . Keeping these roles separate gives the prover fast base field storage and gives the verifier a large challenge space.
The extension-opening reduction explains how Akita later turns such an extension field claim into the packed base field claim needed by the folding protocol.
The cyclotomic ring
For a power of two , Akita uses the ring
An element is a polynomial with at most coefficients:
The quotient by means that . Any term whose degree reaches wraps around with a minus sign. This is called negacyclic reduction.
Take as a small example. Then
The implementation stores the coefficients in ascending degree order. The
ring element is stored as [2, 3, 0, -1], with each entry reduced
in the base field.
CyclotomicRing<F, D> owns this representation. Its ordinary multiplication
computes negacyclic convolution. Its sigma method applies an automorphism
for an odd . Its sigma_m1 method applies
, which appears in inner products and opening reduction.
Why one ring element holds many coefficients
A matrix over is also a structured matrix over . One ring multiplication acts on base field coefficients at once. This structure is what lets Akita use Module-SIS commitments without storing an unrelated scalar matrix entry for every pair of field coordinates.
The ring dimension is not an application parameter. Generated schedules choose it for each matrix role and fold level. Current production schedules begin at and may use larger powers of two. Different roles in one proof may use different dimensions.
Splitting the ring for fast arithmetic
Some primes let factor into smaller irreducible polynomials. Suppose is a power of two and
Then splits into irreducible factors of degree . The Chinese remainder theorem identifies the ring with a product of smaller extension fields:
Arithmetic can move to these factors, perform smaller pointwise operations, and reconstruct the result. Akita's NTT and CRT kernels use this structure. The NTT and CRT chapter explains the transform and the exact integer reconstruction paths.
The amount of splitting also affects security conditions. A larger can make arithmetic faster, but it tightens the coefficient bound that guarantees a short nonzero ring element is invertible. Akita fixes the prime and challenge families together, then validates them as configuration data.
Embedding the challenge field in the ring
The extension field used by a small field configuration must interact with the ring operations used by the folding protocol. Akita uses a genuine subfield of , rather than treating a list of extension coordinates as unrelated ring coefficients.
For the power of two extension degrees used by Akita, this subfield has a fixed
basis inside the ring. The Rust types FpExt2, FpExt4, and FpExt8 implement
the corresponding arithmetic. The degree 4 and degree 8 types use the same
cyclotomic subfield basis used by trace reduction. There is no second quartic
representation that an integrator must choose between.
This alignment provides two operations used by the protocol:
- A base field value embeds into the constant coordinate of the extension.
- An extension field vector can be packed into the ring so that a trace of a ring product recovers the intended field inner product.
The implementation keeps one canonical coordinate order for both operations. Serialization and packed arithmetic use that same order.
The concrete extension bases
Let
inside , where is the extension degree. The degree-2 and degree-4 production extensions use these elements as their stored basis.
For , . Writing , multiplication in the basis is
The implementation computes the cross term with Karatsuba, using three base products for a general quadratic non-residue. Squaring uses two products:
For , the stored basis is . Its products follow
with , , and . For example,
These identities define the direct coefficient formulas used by FpExt4.
Quartic inversion temporarily regards the same element as two values in the
quadratic subfield generated by , where . It computes a norm,
performs one base-field inversion, and converts the result back to the same
four stored coordinates. The tower is an inversion method only; it does not
create an alternate quartic representation.
The degree-8 type follows the same ring-subfield basis pattern. Current
production fp32, fp64, and fp128 schedules use extension degrees 4, 2,
and 1 respectively, while the degree-8 implementation supports shared
algebra and tests.
Trace projection in the same basis
For the subgroup
Akita computes
The fixed ring is isomorphic to the degree- extension. Because the extension coordinates already use the ring-subfield basis, trace projection, extension arithmetic, serialization, and field-to-ring packing all agree on one coordinate system. The implementation does not convert through a power basis before applying the trace.
The map psi_embed places extension elements in one ring element by a
fixed set of shifts. Together with the involution , it gives
the inner-product identity used by the evaluation-trace path:
The evaluation-trace chapter explains how the verifier evaluates the resulting trace weight without constructing the prover's trace table.
Centered coefficients and norms
Security bounds treat a field residue as a small signed integer when possible. The centered representative of a value modulo is the unique integer in that represents it.
For a ring element with centered coefficients , Akita uses three common norms:
The infinity norm controls the largest coefficient. The one norm controls a simple bound on how much multiplication by a sparse challenge can increase a coefficient. The Euclidean norm gives a tighter whole-vector measure when the protocol proves the corresponding physical norm.
For example,
This inequality explains why Akita records the one norm of a fold challenge and the infinity norm of a response. Their product bounds the coefficients of the resulting collision vector.
Challenge subrings and coefficient packing
Some folds use a challenge in a smaller ring while the committed data remains in a larger ring. Let the extension field have degree , and suppose . Akita uses
as the challenge subring and embeds it into by
This map is valid because . It inserts the challenge coefficients at fixed positions in the coefficient ring. The other coefficient lanes remain explicit.
The embedding preserves the coefficient norms of the challenge. It also preserves invertibility. These properties let the protocol use a compact challenge without changing the security bound applied after embedding.
The root fold and ring switching chapter shows the full coefficient grid and the current packed proof relation.
Implementation and review map
| Question | Primary source |
|---|---|
| How is a ring element stored and multiplied? | crates/akita-algebra/src/ring/cyclotomic.rs |
| Which extension types exist? | jolt-field::solinas (FpExt2, FpExt4, and FpExt8) |
| How are base values lifted into an extension? | jolt_field::ExtField and the Solinas extension implementations |
| Which field and extension does a preset use? | crates/akita-config/src/proof_optimized/ |
| Which ring dimensions may a preset schedule use? | The A_RING_DIMENSIONS, B_RING_DIMENSIONS, and D_RING_DIMENSIONS declarations in each preset |
| How is subring coefficient packing validated? | crates/akita-params/src/layout/subring_packing_geometry.rs and crates/akita-types/src/subring_coefficient_packing.rs |
| How are subfield embeddings and traces checked? | crates/akita-types/src/field_reduction.rs |
A review should check that all representations agree on four facts. The prime must match the selected modulus profile. Extension coordinates must use one canonical basis and order. A schedule may select only dimensions admitted by its configuration. Every optimized ring operation must match the scalar negacyclic result.
Field arithmetic
Akita spends most of its prover time adding and multiplying field elements. The representation of those elements therefore affects nearly every higher level operation: multilinear evaluation, sum-check, gadget decomposition, and ring multiplication. The arithmetic library also supplies a smooth FFT and Reed--Solomon extension utility for tests and benchmarks.
The production configurations use three pseudo-Mersenne prime fields. A pseudo-Mersenne prime has the form
[ q = 2^k-c ]
for a small positive integer (c). This shape lets the implementation reduce wide products by multiplication with (c), rather than by a general division or Montgomery reduction.
The production field families
The base field stores the committed polynomial. The challenge field contains the random evaluation points used by the protocol.
| Family | Base-field modulus | Challenge field |
|---|---|---|
fp32 | (2^{32}-99) | degree-4 extension |
fp64 | (2^{64}-59) | degree-2 extension |
fp128 | (2^{128}-2^{32}+22537) | base field |
All three challenge fields therefore have about 128 bits. The fp128 modulus
also has a smooth multiplicative subgroup used by the arithmetic library's
Reed--Solomon extension utility. NTT, CRT, and fast ring
arithmetic describes that separate transform.
The Solinas module registers additional pseudo-Mersenne fields for auxiliary
algorithms, tests, and benchmarks. A registered arithmetic type is not by
itself a production Akita configuration. The selected CommitmentConfig and
its generated schedule determine the fields used by a proof.
Canonical residues
Akita stores a base-field element as its canonical integer in ([0,q)). It does not use Montgomery form. For the 32- and 64-bit fields this is one native word. The 128-bit field uses two little-endian 64-bit limbs.
This representation makes conversion to centered integers and power-of-two digits direct. If (b=2^L), the low unsigned digit is simply
[ u=x\mathbin{&}(b-1). ]
The balanced digit is (u) when (u<b/2), and (u-b) otherwise. The gadget-decomposition chapter develops the full carry rule and the asymmetric final digit range.
Addition and subtraction
There are two machine-level cases.
When (k) is smaller than the storage-word width, two canonical residues can be added without overflowing that word. The implementation conditionally subtracts (q) to return to ([0,q)). The same one-word structure supports subtraction with a conditional correction after a borrow.
The production fields instead fill their storage width: (k=32), (64), or (128). An overflowing sum has lost one copy of (2^k). Because
[ 2^k \equiv c \pmod q, ]
the implementation folds the carry back as (c), then performs the remaining
canonical correction. Subtraction similarly uses the borrow flag to restore
the modulus. The 128-bit implementation has portable two-limb routines and
architecture-specific routines behind its asm feature; both preserve the
same canonical representation.
Multiplication by two Solinas folds
Write a nonnegative integer as
[ x=x_{\mathrm{lo}}+2^k x_{\mathrm{hi}}, \qquad 0\le x_{\mathrm{lo}}<2^k. ]
One Solinas fold replaces it with
[ \operatorname{fold}(x)=x_{\mathrm{lo}}+c x_{\mathrm{hi}}. ]
The two values are congruent modulo (q). A product of canonical residues is smaller than (2^{2k}), so the production multiplication path applies this fold twice. The field types enforce
[ c(c+1)<q, ]
which bounds the second folded value tightly enough for one final canonical correction.
For the 128-bit field, the unreduced product occupies four 64-bit limbs. The first fold combines the high two limbs with the low two through (c); the second fold handles the remaining overflow and canonicalizes. Because its Solinas constant is below (2^{32}), every multiplication by (c) still fits the two-limb folding design.
The 128-bit field also implements a fused operation
[ a b+d \pmod q. ]
It adds the canonical value (d) to the wide product before reduction, then runs one Solinas reduction on the combined value. Polynomial evaluation and other multiply-accumulate loops can therefore avoid reducing (ab) and then reducing the following addition separately.
Deferred reduction
Reducing after every product is unnecessary when an entire inner product has a known integer bound. The field library exposes unreduced product types and accumulators for this purpose.
A hot loop widens each product, adds it to an accumulator whose lanes cannot overflow for the admitted number of terms, and reduces once at the end. Some paths use separate positive and negative accumulators so that signed small coefficients do not require a field reduction at every step. Extension-field accumulators apply the same idea coordinate by coordinate.
The admissible number of terms is an arithmetic contract, not a tuning hint.
Commitment kernels use F::MAX_COMMIT_ACCUMULATIONS, while CRT matvecs use the
explicit reconstruction bound in the NTT and CRT chapter.
When a row is longer, the implementation ends the current accumulation chunk,
reduces it, and continues. It never relies on a wide accumulator being
effectively unbounded.
Product accumulators
A product accumulator stores each base- limb sum in its own u128 slot.
The slots use wrapping addition and subtraction. Reduction later reads each
slot as an unsigned integer and propagates carries between limbs. The result is
exact only while the final mathematical value of every slot remains below
2^128; this headroom is established separately for each concrete product
formula.
| Product | Accumulator | Proven term headroom |
|---|---|---|
| fp32 by fp32 | 2 u128 slots | 2^64 |
| fp64 by fp64 | 2 u128 slots | 2^64 |
| fp128 by fp128 | 4 u128 slots | 2^64 - 1 |
fp128 by u64 | 3 u128 slots | 2^64 - 1 |
| fp32 degree-4 extension product | 4 u128 slots | 2^61 |
| fp64 degree-2 extension product | 4 u128 slots | more than 2^62 |
The extension accumulators fuse reduction by the extension polynomial into the per-coordinate formulas. Subtractive coordinates receive a fixed multiple of the base-field modulus squared before accumulation, preventing unsigned underflow without changing their residue.
Small signed linear accumulators
A different representation serves matrix products with small signed
coefficients. It splits each canonical field element into 16-bit pieces stored
in signed i32 lanes: 2 lanes for fp32, 4 for fp64, and 8 for fp128. Scaling a
field value by a small signed digit scales each lane directly. Fresh lanes have
magnitude below 2^16, so at least
same-sign additions fit. More generally, k terms scaled by magnitude s are
admitted only when
Reduction propagates signed carries through the 16-bit lanes and then applies the field's Solinas reduction. These lanes use ordinary non-wrapping arithmetic; debug builds also trap an accidental lane overflow.
Uniform field sampling
Field::random uses exact rejection sampling. For a modulus with (k)
significant bits, each attempt reads exactly (\lceil k/8\rceil) little-endian
bytes, masks unused high bits, and accepts the candidate only when it is below
the modulus.
This rule matters for reproducible setup generation. Reducing a fixed-width random integer modulo (q) would introduce a small bias. Rejection sampling does not: every field element has the same probability. It also gives a canonical byte-consumption rule for every page of the public setup stream.
Extension arithmetic
An extension element is stored as its canonical base-field coordinates. The degree-2 implementation uses Karatsuba multiplication and a specialized squaring formula. The degree-4 and degree-8 implementations use the same cyclotomic subfield basis consumed by Akita's trace maps. They do not maintain a second wire or storage basis.
The quartic inverse is internally computed through its quadratic subfield, reducing inversion to one base-field inverse. This is an arithmetic algorithm, not another representation of the element. See Cyclotomic rings and extension fields for the basis and multiplication relations.
Implementation and review map
The field code is supplied by Akita's pinned jolt-field dependency.
| Property | Primary source |
|---|---|
| Registered pseudo-Mersenne types and exact rejection sampling | solinas/mod.rs |
| 32- and 64-bit word arithmetic | solinas/word.rs |
| 128-bit two-limb arithmetic and fused multiply-add | solinas/fp128.rs |
| Unreduced products and accumulators | solinas/unreduced.rs |
| Extension arithmetic | solinas/ext.rs |
| Production field selection | crates/akita-config/src/proof_optimized/ |
A field change must preserve canonical encoding, exact sampling, centered conversion, extension-coordinate order, and the bounds assumed by every deferred accumulator. Differential tests compare specialized arithmetic with the ordinary field operations.
NTT, CRT, and fast ring arithmetic
Status: current narrative. This page documents the implemented CRT and NTT paths, including the AVX-512IFMA exact cache.
Akita computes ring products by mapping each ring to several smaller prime fields. It performs a negacyclic NTT in each field, multiplies matching evaluations, applies an inverse NTT, and reconstructs the centered result with the Chinese remainder theorem. The same representation supports matrix matvecs over balanced signed digits.
The protocol fields and the CRT fields have different jobs. Protocol values live in the pseudo-Mersenne fields described in Field arithmetic. The smaller CRT primes are auxiliary compute fields chosen to provide roots of unity for each active ring degree. They do not change the statement being proved.
Deferred reduction and balanced digits
The commitment matvec first decomposes field coefficients into balanced base (2^L) digits. A digit has the exact interval
[ [-2^{L-1}, 2^{L-1}-1]. ]
Bases through (L=8) fit in i8. Bases from (L=9) through (L=16) fit
in i16. The NTT cache selector receives the resulting absolute coefficient
bound directly. It does not infer the bound from a label such as L10.
Code: crates/akita-algebra/src/ring/cyclotomic/decomposition.rs and
crates/akita-types/src/ntt_cache/.
CRT and NTT representation
For a ring of degree (D), each CRT prime supplies a primitive root of order (2D). The forward transform multiplies by the negacyclic twist and then performs a decimation in frequency transform. The inverse performs the inverse decimation in time stages, applies the inverse scale, and removes the twist. The forward and inverse order avoids a separate bit reversal.
The ordinary production profiles use 30 bit CRT primes stored in i32 limbs:
| Field tier | CRT primes | Base representation |
|---|---|---|
| Q32 | 2 | 2 i32 residues |
| Q64 | 3 | 3 i32 residues |
| Q128 | 6 | 6 i32 residues |
The pointwise products and inverse transforms run independently for each CRT
prime. Garner reconstruction then combines the residues into the protocol
field. The optional prime 12289 is an exactness tail. It supports every
protocol ring degree through D = 2048 and is added only when the base CRT
product does not meet the requested bound.
What AVX-512 means in the current implementation
Akita has two different AVX-512 paths. They must not be described as one backend.
The ordinary i32 NTT path uses the scalar reference implementation or the
runtime selected x86 implementation. AKITA_SCALAR_NTT=1 forces the scalar
path. The x86 transforms are written once over a vector-width trait and
instantiated at 256 and 512 bits. Both use radix-4 passes whose butterfly
half length is at least 16, followed (forward) or preceded (inverse) by a
256-bit kernel that runs the last four or five stages in registers. Degrees
below 64 use the scalar transforms. Runtime dispatch selects the AVX2
instantiation. AKITA_AVX512_NTT=1 opts into the 512-bit transforms and
pointwise kernels on hosts with avx512f, avx512dq, and avx512bw. On the
measured AMD Zen 4 host, whose 512-bit units are double-pumped, the 512-bit
transforms were slower than AVX2 up to D256 and at most 2% faster at D1024,
and single-threaded proving did not get faster, so they are not the default.
The second path is AVX-512IFMA. It is used for exact signed NTT caches,
including selected dense q128 commitments whose digits fit in i8. The
selector enables it only when all of the following hold:
- the process has
avx512f,avx512dq, andavx512ifma; AKITA_SCALAR_NTTis not set to1;- the ring degree is
D64throughD2048; and - the exact cache request can be represented by the selected IFMA CRT product, with an optional exactness tail where that profile supports one.
The IFMA kernels use 512 bit vectors with eight u64 lanes. The instruction
family uses a 52 bit radix internally. The selected CRT primes are each below
(2^{50}), so the stored canonical residues are 50 bit values. They are NTT
primes, not the protocol field moduli:
| Prime | Value | Distance below (2^{50}) |
|---|---|---|
| (p_0) | 1125899906826241 | 16383 |
| (p_1) | 1125899906629633 | 212991 |
| (p_2) | 1125899905744897 | 1097727 |
The exact cache uses the smallest CRT representation that meets the strict CRT bound:
| Field tier | IFMA residues | IFMA selection rule |
|---|---|---|
| Q32 | 1 u64 residue | Use the base residue when it fits. Add 12289 when the base does not fit but the mixed product does. Otherwise use the ordinary Q32 profile. |
| Q64 | 2 u64 residues | Use the IFMA form only when the two base residues fit. Otherwise use the ordinary Q64 profile, which can add 12289. |
| Q128 | 3 u64 residues | Use the base residues when they fit. Otherwise add 12289 when that product fits, else the 30-bit prime 1073707009 when that product fits. Otherwise use the ordinary Q128 profile. |
For the full signed i16 bound, the one prime Q32 base is not sufficient at
the eligible degrees, so Q32 exact caches use the mixed tail. The two prime Q64
base supports much larger widths without a tail. The three-prime Q128 base is
roughly 150 bits. Adding 12289 raises the exact reach to roughly 163.6 bits and
the 30-bit tail to roughly 180 bits, matching the portable six-prime profile.
The 14-bit tail is preferred whenever it suffices: its transforms and pointwise
products run at twice the SIMD lane count of the 30-bit tail. This is why one
AVX-512IFMA host can use different cache representations for different field
and schedule shapes.
This representation is used by ExactNegacyclic cache requests. Ordinary
Negacyclic, Cyclic, and BothTransforms requests use the selected i32
profile. The exact selector uses the field modulus, ring degree, matrix width,
and signed RHS bound. It does not select IFMA merely because the host has
AVX-512.
Dense q128 commitments add one further performance rule. If the complete row
exceeds the three-prime IFMA capacity but fits after adding a tail, an eligible
AVX-512IFMA host accumulates the row exactly. This avoids repeatedly
transforming and reconstructing many small chunks. Scalar, AVX2, and NEON
hosts keep the chunked i8 path, which is faster and uses less prepared-cache
memory on those architectures. The rule depends on CPU capability and the
capacity bound, not on a machine name or a fixed problem size.
The IFMA matrix stores one transformed negacyclic matrix for each selected
50 bit prime. When a Q128 tail is needed, the cache stores a shorter prefix of
the same matrix under 12289, or under the 30 bit prime 1073707009 when base plus
12289 is insufficient. The matvec transforms the signed
i16 RHS, accumulates pointwise products, reconstructs with all selected
residues, and returns canonical protocol field elements. The tail does not
change setup bytes, proof bytes, transcript bytes, or setup digests.
Code: crates/akita-algebra/src/ntt/ifma52.rs,
crates/akita-algebra/src/ntt/ifma52/x86.rs,
crates/akita-types/src/ntt_cache/exact.rs, and, for the tail transforms,
crates/akita-algebra/src/ntt/avx/transform.rs.
Accumulation capacity and chunking
Let q be the protocol field modulus, D the ring degree, W the number of
matrix columns accumulated before reconstruction, B the maximum absolute
value of a signed RHS coefficient, and P the product of the active CRT
primes. Each output coefficient is a signed sum of at most D products per
matrix column. The strict condition for centered reconstruction is
2 * W * D * floor(q / 2) * B < P
If the base product does not satisfy this condition, exact preparation adds the 12289 tail when the combined product does satisfy it. If neither product is sufficient, preparation rejects the request. The same capacity calculation is used by cache preparation, verifier warming, runtime matvec checks, and tests.
Large matrix operations can split their work into chunks and reconstruct after each chunk. This keeps every intermediate result inside the same bound. The cache key records the ring degree, transform domain, and required prefix. A stronger exact request can retain a tail prefix for a later weaker request.
On portable, AVX2, and NEON hosts, exact caches use the field selected i32 profile and add the 12289 tail when needed. On eligible AVX-512IFMA hosts, the selector may use the 50 bit u64 profiles described above. These are different storage choices for the same centered CRT contract.
Code: crates/akita-algebra/src/ntt/crt.rs,
crates/akita-types/src/ntt_cache/, and
docs/crt-ntt-capacity-profile.md.
Limb-split exact products
A field-sized CRT product pays for the full width of every matrix entry. For a q128 exact product that is six i32 primes, plus a tail, or three IFMA primes. Each prime costs one RHS transform per column and one pointwise product per output row. When a matrix has only a few output rows, the RHS transforms dominate, and a narrower representation is cheaper.
A prover exact cache can therefore store each public entry as balanced limbs. Let (n) be the bit length of (q). A centered entry (A), with (|A| < q/2), is written as
[ A = \sum_{l=0}^{L-1} 2^{bl} A_l, \qquad |A_l| \le 2^{b-1}, \qquad bL \ge n + 1. ]
Each limb row accumulates exactly under two CRT primes. The capacity condition above applies with (2^b) in place of (q), so the limb bound replaces the field bound. Portable, AVX2, and NEON hosts use the two i32 Q32 primes. Eligible AVX-512IFMA hosts use the first two 50 bit IFMA primes. The matvec reconstructs every limb product (y_l = A_l \cdot v) as an exact integer and returns (\sum_l 2^{bl} y_l) in the protocol field.
The selector picks the smallest (L \ge 2) whose limbs fit the two-prime capacity. At the q128 modulus with (D = 512), a width of 1536, and an 11 bit signed digit, the i32 primes need (L = 5) limbs of 26 bits. The IFMA primes need (L = 2) limbs of 65 bits.
The limb form transforms the RHS under two primes instead of the full CRT set. It also computes (L) times as many pointwise products per output row. The selector compares both plans in units of one prime-row pointwise product. It charges 6 units for an i32 prime transform and 2 units for an IFMA prime transform. It uses limbs only when their estimated cost is strictly lower. With these weights, limbs win for few-row q128 and q64 products and lose once many rows share each RHS transform. The q32 base product uses only two i32 primes and a tail, so at the example shape limbs win only for a single row.
Limbs also change the memory footprint:
| Profile | Base residue bytes per coefficient | Limb residue bytes per coefficient |
|---|---|---|
| i32, q128 | 26 with the 12289 tail | 40 at (L = 5) |
| IFMA, q128 | 28 with the 30 bit tail | 32 at (L = 2) |
The limb form is used only for prover caches prepared without a verifier tail prefix. Verifier warmed caches, compression caches, and the prepared verifier artifact keep the base representation. The choice therefore changes prover time and prepared-cache memory, but not setup bytes, commitment bytes, proof bytes, transcript bytes, or setup digests.
Code: crates/akita-types/src/ntt_cache/limbs.rs and
crates/akita-types/src/ntt_cache/exact.rs.
Smooth-subgroup FFT for Reed--Solomon encoding
The CRT transforms above accelerate multiplication in (\mathbb F_q[X]/(X^D+1)). Reed--Solomon encoding is a different operation: it evaluates a polynomial at many points in the protocol field itself.
The production fp128 modulus
[ q=2^{128}-2^{32}+22537 ]
was chosen in part because (q-1) contains the smooth factor
[ 17496=2^3\cdot 3^7. ]
primitive_nth_root::<F>(n) checks that n is positive and divides the
configured smooth subgroup order, then derives a root of order n from the
field's configured generator. Invalid requests panic.
SmoothDomain::new(omega, n) takes that caller-supplied root and size, factors
the size, and precomputes the execution plan. Its primitivity check is a debug
assertion; it does not provide production validation of an arbitrary supplied
root. Construction can panic, including when omega is zero or n is not
invertible in the field.
Other protocol fields do not implement SmoothFftField merely because they are
pseudo-Mersenne fields.
Iterative mixed-radix execution
For
[ n=f_0f_1\cdots f_{s-1}, \qquad f_i\in{2,3,5,7}, ]
the forward transform first applies the mixed-radix analogue of bit reversal. It then sweeps the stages from small to large, running an in-place radix- (f_i) butterfly at each stage. The inverse uses inverse roots and multiplies the result by (n^{-1}).
The domain precomputes both digit-reversal positions and stage twiddles. Repeated encoding therefore performs no factorization, root search, or per-stage allocation. A reusable workspace holds the two transform buffers.
Small-radix kernels
Each butterfly has a specialized kernel. Radix 2 is the ordinary sum and difference. Radix 3 uses (1+\omega+\omega^2=0) to reduce the number of field multiplications. Radix 5 and radix 7 use precomputed Winograd constants and fixed addition chains instead of a dense quadratic-size DFT.
The configured fp128 subgroup uses only radices 2 and 3. Radix-5 and radix-7
kernels are implemented, but the current tests do not exercise them. Direct-DFT
comparisons cover the selected sizes 2, 3, 6, 8, 9, 18, 24, 27, 54, 81, 162,
243, 486, and 729. Separate tests check root orders at selected sizes through
17496, forward/inverse round trips at 243, 1458, and 2187, and coset extension
from 243 to 2187. These checks do not establish parity for every subgroup
divisor.
Coset extension
Suppose evaluations are known on a subgroup of size (k), and the target Reed--Solomon domain has size (kB). The implementation first applies the inverse size-(k) transform to recover coefficients. For each of the remaining (B-1) cosets, it multiplies coefficient (i) by a coset shift raised to (i), then applies the forward size-(k) transform. The output is stored in coset-major order.
This flow reuses one SmoothDomain and one workspace across all cosets. It
returns only the k(B-1) evaluations on the additional cosets; the original
subgroup evaluations are not repeated. The smooth FFT and Reed--Solomon
extension are exported arithmetic utilities currently exercised by unit tests
and crates/akita-pcs/benches/fft_smooth.rs. The production prover and verifier
do not call this encoding path.
Code: crates/akita-algebra/src/fft.rs.
Further reading
specs/large-digit-ntt-infrastructure.mdrecords the implemented exact signed digit and terminal NTT contract.book/src/usage/profiling.mddocuments the NTT matvec benchmarks and their cache labels.docs/crt-ntt-capacity-profile.mdrecords the generated portable i32 capacity table. It does not replace the host dependent IFMA rules on this page.
Gadget decomposition
Akita often works with coefficients, the individual numbers in a polynomial, that can be almost as large as the field modulus. The modulus is the prime number around which field arithmetic wraps. Akita later locks these coefficients into short commitments. Its security calculations and matrix sizes need an explicit bound for every committed value.
Gadget decomposition replaces one large coefficient with several small signed integers called digits. The original coefficient can be recovered from those digits. Akita can therefore run its matrix commitments with small, known input bounds without losing the original value.
This chapter first explains the operation for one ordinary integer. It then shows the general equation, the exact range that a fixed number of digits can represent, and the places where Akita uses different decomposition depths.
Ways to read this chapter
The explanation through the exact range of a digit list is the common foundation. After that, different readers may want different details.
| If you want to | Continue with |
|---|---|
| Learn the idea without prior knowledge of proof systems | The chapter in order, starting with the base 4 example |
| Supply values to Akita | Where Akita uses decomposition and source width and source shape |
| Change or review the implementation | How digits are stored, the code path, and the review checklist |
| Audit how the protocol rule reaches the shipped code | From the protocol rule to the code |
| Study performance | From one coefficient to a vector and how digits are stored |
The later sections do not introduce a different version of decomposition. They show how the same mathematical rule becomes an input contract, a public schedule choice, a memory layout, and an optimized routine.
The values being decomposed
Akita performs most arithmetic in a finite field. A field element is stored as an integer from to , where is a prime number called the modulus. Arithmetic wraps around modulo . For example, and represent the same field element.
A ring element in Akita is a polynomial whose coefficients are field elements. Decomposing a ring element means decomposing each of its coefficients. The same coefficient operation is also used on flat vectors of field elements.
A polynomial commitment is a short value that fixes a polynomial. After the prover publishes the commitment, the prover should not be able to claim that it committed to a different polynomial. A witness is the data used to make a proof. In Akita, several commitment and opening witnesses contain decomposed coefficients.
Akita's lattice commitment multiplies witness coefficients by a public matrix. The security calculation needs an upper bound on those coefficients. A larger bound can require a matrix with more output rows, which makes the commitment or proof larger. Decomposition gives the matrix small inputs with an exact bound while preserving the original coefficient modulo .
A small example
Choose base . Ordinary base 4 digits range from 0 to 3. Akita instead uses the balanced signed digits
The integer 19 has the following balanced base 4 decomposition:
Akita records the digits from the least significant position to the most significant position. The digit list for 19 is therefore .
Negative values work in the same way. For example,
so its digit list is .
These equations also hold for field elements because Akita checks the result modulo . A field element has many integer representatives that differ by a multiple of . Before decomposition, Akita chooses a signed representative that fits the available balanced digit range.
The general decomposition rule
Akita uses bases that are powers of two. It writes
where is called the basis exponent in the code. The balanced digit set is
The number of digits is written as . A coefficient is decomposed into digits that satisfy
The symbols have the following meanings.
| Symbol | Meaning |
|---|---|
| The prime field modulus | |
| The decomposition base | |
The base 2 logarithm of , stored as log_basis | |
| The number of digits, also called the decomposition depth | |
| The signed digit at position |
The digit at position zero has weight 1. The next digit has weight . Each later position multiplies the weight by another factor of .
From one coefficient to a vector
The gadget matrix records the powers of used to rebuild every coefficient. For coefficients, it is written as
Here is the square identity matrix with rows and columns. It has ones on its diagonal and zeros elsewhere. The tensor product symbol means that each coefficient gets its own copy of the power vector . Multiplying this matrix by the digits rebuilds the original coefficients modulo .
The matrix formula groups all digits of one coefficient together. The flat decomposition function in the code stores the same data in digit major order. It stores the first digit of every coefficient, then the second digit of every coefficient, and continues in that order.
For the two coefficients from the example above, the digit planes are
The flat output is therefore . This order lets the prover process one digit plane across many coefficients at once.
The exact range of a digit list
A fixed number of digits cannot represent every integer. The largest possible absolute value depends on the base and the number of digits.
Add the weights of all digit positions and call the result :
The most negative digit at every position is . The largest positive digit is only . Therefore, digits represent every integer in
where
The interval extends farther in the negative direction. This is not a rounding error. The digit set contains , but it does not contain .
For base 4 with three digits, . The negative endpoint is . The positive endpoint is . The exact range is therefore .
The code provides two kinds of range helper. The exact helper returns None
for an endpoint when the true mathematical value is larger than any u128.
In that result, None means that no u128 coefficient can exceed the
endpoint. A separate helper returns a finite value when its calculation would
overflow. That finite value is safe for estimates, but code that accepts or
rejects a coefficient uses the exact helper.
How Akita chooses the number of digits
The decomposition depth must be large enough for the value being decomposed. Akita uses two related rules because a full field element and a source with a smaller declared bound have different ranges.
Full field elements
Let be the number of bits needed for field elements. A full field decomposition uses
The ceiling brackets mean that the fraction is rounded up to the next integer. For example, a field with 128 bits and basis exponent uses 43 digits. Forty two digits cover only 126 bit positions, so one more digit is required.
There is one edge case when . A symmetric signed interval can appear to require an extra digit even though every field value already has a valid representative. Akita uses the smaller of the exact positive endpoint and as its centering threshold in this case. Residues above that threshold are represented as negative integers by subtracting . This lets the full field path keep the rounded up formula above.
Sources with a smaller bound
Some committed sources are known to be much smaller than a general field element. Akita records their allowed signed width as . A width of means the interval
Akita first tries digits. It then checks the exact positive endpoint . If that endpoint is too small, Akita adds one digit.
A concrete case shows why this check is needed. Let and , so the base is 8. The declared signed interval is . Two balanced base 8 digits represent only . The negative side is wide enough, but the positive side stops at 27. Akita therefore uses three digits.
A nonnegative value that may be as large as needs signed width
. This extra bit records the sign. A source that may contain any
u64 value therefore declares width 65, not 64.
Some parts of the protocol have an exact bound on the largest absolute coefficient instead of a signed bit width. This bound is often written as an infinity norm. Akita tries increasing depths and selects the first exact digit range that contains both the positive and negative bound.
Where Akita uses decomposition
A proof starts with the values supplied by the application. Akita calls these the root source. An opening proves that a committed polynomial has a claimed value at a chosen point. A fold reduces the current claims to an opening of a new recursive digit witness. The full witness includes auxiliary data and need not be smaller than the input, especially at the root.
These values need different decomposition depths.
| Value | Why it is decomposed | Bound used for its depth |
|---|---|---|
| Root committed source | It is the application data entering the first commitment | log_commit_bound |
| Recursive committed source | It is the recursive digit witness produced by an earlier fold | The source bound stored by the schedule |
| Opening value | It is used to prove a claimed polynomial evaluation | log_open_bound or the full field width |
| Setup prefix | It contains public setup field elements used by a later fold | The full field width |
| Folded response | It is the response produced during one fold | The exact response bound stored by the schedule |
The schedule is a public plan chosen before proving. It records the bases, digit counts, matrix sizes, and other values that the prover and verifier must use at each fold. The verifier reads the same digit counts from the resolved schedule. It does not trust a digit count supplied by the proof.
An application using a standard preset does not call the decomposition routine or choose a digit count directly. It declares its source representation and uses a preset whose planner resolves these choices into the schedule. A custom configuration must keep the source class, source bound, basis, and resulting depth consistent. Akita rejects the source at commitment time if that contract does not hold.
Source width and source shape are separate
Akita records both a numeric bound and a source class. The bound says how large each coefficient may be. The class says what pattern the coefficients must follow.
BalancedSignedDigit is the general bounded signed source class.
UnitOneHot is more specific. Its coefficients are 0 or 1, and each configured
chunk contains at most one coefficient equal to 1. A dense vector of zeros and
ones does not satisfy this class merely because each coefficient is small.
For this reason, log_commit_bound == 1 does not select UnitOneHot. The class
must say UnitOneHot explicitly. For a bounded BalancedSignedDigit source,
the accepted coefficient interval is the intersection of two ranges:
- The interval declared by
log_commit_bound. - The interval that the scheduled number of digits can represent.
The code that creates the commitment checks both ranges. It rejects an out of
range coefficient instead of silently dropping high digits. The UnitOneHot
path separately checks that every value is 0 or 1 and that each chunk has at
most one value equal to 1.
How digits are stored
The largest digit depends on , so Akita chooses a signed integer type
that can hold every digit. In Rust, i8 is a signed integer with 8 bits and
i16 is a signed integer with 16 bits.
| Basis exponent | Balanced digit interval | Rust storage |
|---|---|---|
| 1 to 8 | i8 | |
| 9 to 16 | i16 |
The basis exponent is not the base itself. For example, means base , with digits from to 511. It does not mean base 10.
Production schedule validation keeps opening bases in the i8 range and
inner commitment bases in the i16 range. The current schedule search tries
opening exponents from 3 to 6. It tries inner exponents up to 10 for fields
with 32 bits and up to 11 for fields with 64 or 128 bits.
The ring API can return digits as field elements, i8 values, or i16 values.
For 32 bit fields, the packed i8 function uses SIMD when the processor
supports it. SIMD applies the same operation to several integers at once. The
NEON path on AArch64 processes four field values at a time. The AVX2 path on
x86 processes eight. Both read the standard 32 bit representation directly.
The ordinary fallback processes one value at a time and produces the same
digit major output.
The i8 NTT commitment path next represents each signed digit modulo several
smaller primes. It stores those residues in Montgomery form, which is an
internal representation used for fast multiplication. Converting every digit
inside the matrix multiplication loop would repeat the same work many times.
Akita instead builds a lookup table once for each matrix multiplication. The
table covers the active balanced range and returns the prepared residue for a
digit and a small prime. The fixed i8 table can cover every value from -128
to 127, while each operation initializes only the part needed by its basis.
Path through the code
The main code path is:
DecompositionParamsincrates/akita-params/src/config.rsrecordslog_basis,log_commit_bound, and the optionallog_open_bound.crates/akita-params/src/sis/decomposition_digits.rscomputes the exact digit count for each protocol role.- The generated schedule stores the selected counts in
CommittedGroupParams. crates/akita-algebra/src/ring/cyclotomic/decomposition.rsperforms the coefficient decomposition and rebuilding operation.crates/akita-cpu-backend/src/kernels/linear/decompose.rsuses the packedi8kernel. Wider inner decompositions usecrates/akita-cpu-backend/src/arithmetic/exact_i16.rs.crates/akita-params/src/sis/committed_source.rschecks the accepted source range and source class.
Supporting limits live in these files:
crates/akita-params/src/signed_digit.rsselectsi8ori16storage.crates/akita-algebra/src/ring/crt_ntt_repr/lut.rsprepares signedi8digits for the CRT and NTT commitment path.crates/akita-schedules/src/runtime.rsvalidates schedule basis ranges.crates/akita-config/src/proof_optimized.rsdefines the production search ranges.
From the protocol rule to the code
The equations above define decomposition, but the implementation must make more choices. It decides how many digits each protocol value gets. It chooses the signed integer type and memory order. It also decides which inputs are allowed. The schedule makes these choices public so that the prover and verifier use the same values.
| Property to trace | Explanation in this chapter | Current implementation |
|---|---|---|
| A coefficient is rebuilt from balanced powers of the base | The general decomposition rule and the gadget matrix | decomposition.rs extracts the digits, while digit_math.rs produces the public powers used to rebuild them |
| The asymmetric range and full field centering need no extra digit | The exact range and full field elements | decompose_centering_threshold applies the exact threshold, including the 128 bit overflow boundary |
| Every committed digit is in the balanced set | The balanced digit set | layout/digit_range.rs defines the range polynomial and akita-verifier/src/stages/stage1.rs verifies its sumcheck proof |
| Different protocol values can use different bases and depths | Where Akita uses decomposition | decomposition_digits.rs separates root sources, recursive sources, setup prefixes, openings, and folded responses |
| Prover and verifier use the same choice | The public schedule | The resolved schedule stores each role specific basis and depth in CommittedGroupParams |
| A committed source satisfies the assumptions used to size it | Source width and source shape | committed_source.rs defines the contract and akita-cpu-backend/src/backend/commitment/api.rs enforces its numeric and structural parts |
| Compact extraction and field conversion preserve the same digits | How digits are stored | signed_digit.rs selects i8 or i16, decomposition.rs extracts the digits, and crt_ntt_repr/lut.rs prepares i8 digits for multiplication |
| SIMD extraction agrees with scalar extraction | The fast path and fallback | decomposition/aarch64.rs and decomposition/x86.rs implement the fast paths, while the centering boundary tests compare their public dispatch with the scalar definition |
This table separates the protocol contract from its implementation. The equations and ranges state what must hold. The schedule and source contract state which values Akita accepts. The algebra, prover, and verifier code show how Akita computes and checks those values.
Review checklist
A code review or security audit can follow the mechanism in this order.
- Check that extraction produces digits in and that their weighted sum rebuilds the original coefficient modulo .
- Check the independent verifier boundary. Stage 1 must prove that every committed digit is a member of the same balanced set. Correct prover extraction alone is not enough because a proof may contain malformed data.
- Check that the depth selector covers the correct range for each role. Full field values and smaller signed sources use different centering rules.
- Check that source admission applies both parts of the contract. The numeric interval and the declared source class are independent.
- Check that the resolved schedule, proof layout, prover, and verifier all use the same role specific depth and basis.
- Check that the flat, ring,
i8,i16, scalar, NEON, and AVX2 paths agree on digit order and centering at their boundaries. - Check any performance change against the scalar implementation before relying on benchmark results. A faster layout is only valid if it preserves the same digits and reconstruction.
The focused regression tests are in
crates/akita-params/src/sis/decomposition_digits.rs,
crates/akita-params/src/sis/committed_source.rs, and
crates/akita-algebra/src/ring/cyclotomic/tests.rs. The Stage 1 range topology
tests live in crates/akita-types/src/proof/stage1.rs. Together, these tests
cover the asymmetric field boundary, the exact positive reach, the
intersection of declared and representable source ranges, supported range
proof bases, digit major layout, the wider i16 bases, and agreement between
scalar and SIMD decomposition. These tests are useful evidence, but they do
not replace checking that every protocol caller uses the right public
parameters.
What to remember
Gadget decomposition is an exact change of representation. It does not round a coefficient or change the field element. It replaces one coefficient with small signed digits whose weighted sum gives the original value modulo .
The base controls the size of each digit. The depth controls how many digits are available. Akita chooses both values as part of the public schedule, and the prover must reject any source that does not fit the resulting contract.
Lattices and Module-SIS
Akita's commitments are binding because opening one commitment in two incompatible ways would reveal a short solution to a Module-SIS problem. This chapter defines that problem and shows the reduction with a small example.
The chapter explains the general assumption. The security model explains how Akita prices each concrete matrix and norm bound.
From integer vectors to lattices
A lattice is a set of vectors formed by integer combinations of fixed basis vectors. If the basis vectors are the columns of a matrix , the lattice is
The integer coefficients make this set discrete. A lattice can contain many vectors, but finding a nonzero vector that is unusually short can still be hard in a high dimension.
Lattice cryptography builds security arguments around such short vector problems. Akita uses a structured version over a polynomial ring.
Ring vectors and modules
Let
A vector in contains ring elements. Since each ring element has coefficients, the vector also represents base field coordinates.
A module is closed under addition and multiplication by elements of the ring. For this chapter, it is enough to think of as the set of length ring vectors. Matrix multiplication follows the usual row by column rule, but the entries are ring elements.
The Module-SIS problem
Module-SIS stands for the Module Short Integer Solution problem. Its public input is a matrix
The task is to find a nonzero vector such that
and is short.
There are usually more columns than rows, so a nonzero kernel vector exists as an algebraic fact. The hard part is finding one whose centered coefficients all satisfy the required norm bound.
Akita uses two versions of shortness. In the coefficient infinity norm problem,
In the coefficient Euclidean norm problem,
Both norms are applied to the complete list of centered coefficients.
A small kernel example
Take the deliberately small ring
and the one row matrix
The vector
is in its kernel because
Its centered coefficient list is . Therefore and .
This example is far too small for security. It only shows what a Module-SIS solution looks like. Production matrices use much larger scalar dimensions and bounds selected from generated security tables.
Why commitment collisions reveal a solution
An Ajtai commitment has the form
where is public and is a short ring vector derived from the committed data.
Suppose a prover finds two different short vectors and with the same commitment:
Subtracting the equations gives
Since , the difference is nonzero. Since both openings are short, the triangle inequality gives a bound on . The collision has produced a short nonzero kernel vector for the public matrix.
This is the basic binding argument. The full Akita proof uses weak openings and fold challenges, so its collision bound includes the challenge norm and the accepted response norm. The same structure remains. Two incompatible accepted openings produce a bounded Module-SIS solution.
How the two norms relate
For any vector with centered coefficients,
The first inequality holds because the Euclidean norm includes the square of the largest coordinate. The second holds because every one of the coordinates is at most in magnitude.
The two bounds are related, but they define different security queries. Akita keeps separate generated tables for them.
- The infinity norm route is the standard route and is always available.
- A Euclidean route is used only when the verifier proves or directly checks the complete physical squared norm of the response.
The word physical is important. The security table applies to the actual ring coefficients multiplied by the public matrix. It does not apply to a smaller logical vector before extension coordinates or packed lanes have been expanded.
Matrix rank, width, and security
For , Akita calls the module rank and the ring width. As scalar dimensions, the matrix has rows and columns.
A wider matrix gives the commitment more input capacity, but it also gives an attacker a larger space in which to search for a short kernel vector. Increasing the module rank makes that search harder. The required rank therefore depends on all of the following public values:
- the modulus ;
- the ring dimension ;
- the ring width ;
- the accepted collision norm;
- the security model and target.
Akita has three matrix roles. The A matrix commits to the inner witness. The B matrix compresses or contains later commitment data. The D matrix commits to opening information. Each role has its own width and bound, so the planner prices each role separately.
The production security tables
Akita targets 128-bit quantum security under the ADPS16 quantum LGSA attack model. The estimator runs offline. It searches scalar lattice attack parameters, certifies the accepted width boundary for each supported query, and emits compact tables for the runtime.
The runtime lookup has the following shape:
(security policy, modulus profile, matrix role, ring dimension, norm bound)
-> maximum secure width for each module rank
The planner asks for the smallest rank whose certified width covers the matrix it needs. The generated schedule records that choice. Proving and verification do not run the estimator. If a required table cell is missing, schedule selection fails.
This split keeps expensive floating point attack estimation out of the proof path. It also makes every accepted parameter choice reproducible from checked in generated data and its digest.
The 128-bit value is a claim inside a specific attack model. It is not a count
of physical qubits or a claim that every possible future attack has been
classified. The exact policy name is Quantum128BitADPS16.
What the verifier enforces
The security argument uses the same public bounds that verification enforces. A schedule fixes the matrix parameters, challenge family, digit ranges, and any response norm cap. These values are part of the schedule and instance identity.
For an infinity norm route, digit range checks and the fold response cap give the coefficient collision bound. For a Euclidean route, the proof also checks the squared norm of the complete physical response. A terminal response can be checked directly because the verifier receives its coefficients.
The verifier never accepts a looser bound and then asks the security estimator to price it. The approved table lookup happens before the proof is accepted.
Implementation and review map
| Question | Primary source |
|---|---|
| Which security policy and modulus profiles exist? | crates/akita-params/src/sis/ajtai_key.rs |
| How is the minimum infinity norm rank selected? | min_secure_rank in ajtai_key.rs |
| How is the minimum Euclidean rank selected? | crates/akita-params/src/sis/l2_table.rs |
| Where do generated infinity norm widths live? | crates/akita-params/src/sis/generated_sis_table/ |
| Where do generated Euclidean widths live? | crates/akita-params/src/sis/generated_l2_sis_table/ |
| Where are fold collision bounds computed? | crates/akita-params/src/sis/norm_bound.rs |
| Where are physical Euclidean proof shapes defined? | crates/akita-params/src/sis/physical_l2.rs |
| Where is the offline estimator implemented? | crates/akita-sis-estimator/ |
A security review should follow one generated schedule row from its matrix width and accepted response bound to the exact generated table key. It should then confirm that the verifier checks the same response coordinates and the same cap. A separate table or a duplicated local formula would break that connection.
Multilinear extensions and sum-check
Sum-check lets Akita prove a sum over an exponentially large table without putting that table in the proof. It replaces one claim about all table entries with short polynomial messages and one final evaluation claim.
This chapter builds the protocol from a four-entry example. It then explains the compressed messages and unequal-size batching used by the implementation.
A table is also a polynomial
Consider a table indexed by two bits:
| 0 | 0 | 2 |
| 1 | 0 | 5 |
| 0 | 1 | 7 |
| 1 | 1 | 11 |
There is exactly one polynomial that agrees with this table on the four Boolean points and has degree at most one in each variable. It is the multilinear extension of the table:
The four terms are selectors. At , for example, only the second selector is one, so the polynomial returns .
The general selector for two Boolean vectors is
It is one when and zero at every other Boolean point. For a table , its multilinear extension is therefore
The polynomial also accepts field values that are not bits. This is what makes it useful in a proof. The verifier can derive a random field point from the transcript and ask for one value there.
Table order in Akita
Akita stores Boolean tables in little-endian order. Coordinate is the
least significant index bit, so adjacent entries differ in . The example
above is stored as [2, 5, 7, 11].
Binding replaces each adjacent pair with
The four-entry table becomes a two-entry table. Binding the next coordinate leaves one value, which is . The implementation calls this operation a fold.
multilinear_eval in akita-algebra/src/poly.rs evaluates a table this way.
fold_evals_in_place provides the mutable fold used throughout prover code.
EqPolynomial in akita-algebra/src/eq_poly.rs builds the equality selectors
in the same index order.
What sum-check proves
Suppose the prover claims
where has degree at most in each variable. Directly checking the claim would take evaluations. Sum-check reduces it one variable at a time.
In round zero, the prover sends the univariate polynomial
The verifier checks
It then samples a challenge from the transcript and replaces the claim with . Round one does the same for the next variable:
After rounds, every variable has been bound. The verifier checks the final claim against , computed from the protocol's final oracle values. The large Boolean sum has become one evaluation at a random point.
A complete two-round example
Return to the table [2, 5, 7, 11]. Its claimed Boolean sum is
The first round polynomial sums over :
The verifier checks . Suppose its first challenge is . The new claim is .
The second round polynomial is
Again, . If the next challenge is , the final claim is . Evaluating the original multilinear extension at also gives .
Real challenges are unpredictable field elements derived from the transcript. Small integers are used here only to make every step visible.
Why a false claim is caught
At the start of a round, the previous claim fixes the sum . The prover may try to send a different degree- polynomial that has the same sum. Two distinct degree- polynomials agree at no more than field points. A fresh random challenge therefore exposes that substitution except with probability at most in that round.
Across rounds, the usual bound is
Akita chooses large challenge fields, so this algebraic error is small. The complete security argument also accounts for transcript challenges, commitment binding, and every other reduction. Those pieces are assembled in Security model and parameters.
The extraction argument uses a related fact. A degree- round polynomial is determined by distinct evaluations. If an extractor can obtain accepting continuations from the same transcript prefix, it can reconstruct that round polynomial. This is the special-soundness property used when sum-check is connected to commitment binding.
Akita sends one fewer coefficient
Write a round polynomial as
The verifier already knows the current claim . Since
the linear coefficient is determined by
The proof sends only [c0, c2, ..., cd]. The verifier recovers the missing
linear contribution while evaluating the message at the next challenge. This
saves one field element in every round without changing the protocol.
The types UnivariatePoly and CompressedPoly in jolt-poly own this rule.
akita-serialization preserves Akita's wire encoding. Proof decoding is headerless:
the verifier derives each expected coefficient count from the proof shape
rather than trusting a length supplied by the proof.
Every ordinary round message must retain at least its constant coefficient.
The prover compresses the zero polynomial to [0], including when its full
coefficient vector is empty. An empty compressed message is malformed: the
verifier cannot use it to reconstruct the linear coefficient from the incoming
claim. Both ordinary sum-check drivers check the round count, nonempty messages,
and degree bounds before absorbing any data in their own replay. A caller may
already have absorbed the public statement or batching data before entering a
driver.
A single stored coefficient can still represent a linear polynomial, so its degree estimate is one. Ordinary rounds require a degree bound of at least one, even for constant polynomials. A zero-round proof instead has no messages and leaves the input claim for the final oracle check. These rules differ from equality-factored sum-check, where a valid constant inner polynomial has an empty message and its constant term is recovered from the normalized claim.
Batching several claims
Akita often needs several sum-checks at the same point in the protocol. Running them separately would repeat challenges and round messages. Instead, the transcript derives one random coefficient for each instance and the prover sends the linear combination of their round polynomials.
If all instances have the same number of variables, their initial claims combine as
The same coefficients combine every round polynomial and the final oracle values. A false component is therefore hidden only if the random linear combination happens to cancel it.
Instances with different numbers of variables
The current implementation right-aligns every instance in the longest challenge vector. If the longest instance has variables and one shorter instance has variables, the shorter instance receives constant dummy rounds before its first real round.
A dummy polynomial for running claim is the constant . Its two Boolean evaluations sum to , and evaluating it at any challenge returns . After all dummy rounds, the claim has been divided by . Therefore the batch starts that instance at
The dummy rounds reduce it back to exactly when the instance becomes active. Its real variables then use the suffix
of the shared challenge vector. This is the offset = max_num_rounds - n
rule in batched_sumcheck.rs.
Where to inspect the implementation
| Rule | Implementation |
|---|---|
| Evaluate a multilinear table | akita-algebra/src/poly.rs |
| Build equality-polynomial tables | akita-algebra/src/eq_poly.rs |
| Represent and compress round polynomials | jolt-poly/src/univariate.rs and jolt-poly/src/compressed_univariate.rs |
| Define prover and verifier instance contracts | akita-sumcheck/src/traits.rs |
| Encode proofs and verify ordinary rounds | akita-sumcheck/src/types.rs |
| Batch claims and right-align shorter instances | akita-sumcheck/src/batched_sumcheck.rs |
For a review, check these facts together:
- Table indexing and challenge order agree.
- Every round polynomial respects the declared degree bound.
- The transcript absorbs the claim and round message before sampling the challenge that depends on it.
- Proof decoding derives the round count and message width from trusted configuration.
- The final output claim is compared with the expected oracle evaluation.
- Batched instances use the same coefficients, offsets, and challenge slices on the prover and verifier paths.
The next chapter explains the specialized form used when every summand contains a known equality polynomial.
Equality-factored sum-check
Many Akita identities give extra weight to one point through the equality polynomial:
Ordinary sum-check can prove this claim. Equality-factored sum-check proves the same claim with smaller round messages and a smaller prover table. The saving comes from treating the known equality factor separately from the polynomial that carries the protocol data.
Read Multilinear extensions and sum-check first if the ordinary round check is not yet familiar.
The equality factor splits by coordinate
For one coordinate, define
This is a linear polynomial in . Across all coordinates,
After the first variables have been bound to challenges , their equality contribution is one scalar:
The corresponding full round polynomial has the linear factor
The remaining coordinates stay inside the Boolean sum. The full round polynomial therefore factors as
where is the round polynomial formed from and the equality factors for the still unbound coordinates. Equality-factored sum-check normalizes the already-bound scalar out of the running claim. Its round identity therefore uses directly rather than carrying from one round to the next.
Omit the constant coefficient
Suppose has degree at most . The full polynomial can have degree because is linear. The verifier already knows , so Akita sends coefficients of instead of coefficients of .
There is one more saving. Write
The normalized current claim obeys
The coefficient of is exactly one, independently of . Akita does not send that coefficient. An equality-factored round message stores
[q1, q2, ..., qd]
For the common case where contributes degree two, ordinary sum-check would send three coefficients for the degree-three product . The factored message sends two coefficients for the degree-two inner polynomial .
jolt_poly::OmittedConstantPoly stores this round message, and
akita-serialization encodes it on the wire. A
degree- inner polynomial contributes exactly field elements. Thus every
deployed Akita Stage 1 round, whose inner degree is positive, keeps the same
message width; the valid degree-zero case needs no transmitted coefficient.
The verifier avoids division
The verifier recovers the omitted coefficient by subtraction:
After sampling , it advances the normalized claim as
No inverse or accumulated claim scale appears, and the formula remains valid when or when an earlier equality evaluation vanishes. The final verifier check compares directly with the expected folded oracle value.
The public function advance_eq_factored_claim in
akita-sumcheck/src/single.rs implements these equations directly. The direct
prove_eq_factored_sumcheck and verify_eq_factored_sumcheck functions both
call it, so transcript replay and proof generation cannot drift onto different
update rules.
Avoiding a full equality table
A direct prover can materialize all
values and fold that table in every round.
Akita uses GruenSplitEq instead.
It divides the unbound coordinates, other than the current one, into two halves. For each half it caches equality tables for its remaining suffixes. At a round, the equality weight for table index is reconstructed as
The specialized driver reads the current coordinate and the remaining
tables, then pops one cached table level after binding a challenge.
GruenSplitEq also tracks because other, ordinary sum-check paths
use it to reconstruct the full polynomial ; the normalized
equality-factored verifier does not multiply its claim by this scalar.
Each half has about coordinates. The largest cached table therefore has about entries rather than . Including all smaller cached levels changes only the constant factor. This is a substantial memory reduction for large sum-checks.
GruenSplitEq lives in akita-algebra/src/split_eq.rs. Its tests compare every
reconstructed weight and every fold against a fully materialized equality
table.
When this form applies
The optimization applies when the verifier knows a common equality factor for the sum-check instance. It is especially useful for claims built around one verifier point .
Instances that share the same factor can also share the specialized round logic. A mixed batch with different equality factors cannot omit the same inner coefficient under one common round equation. Such a batch uses ordinary compressed sum-check messages instead. The prover may still use split equality tables internally to save memory.
This distinction matters in review. The equality-table representation is a prover implementation choice. Constant-coefficient omission is specific to the normalized equality-factored identity above; ordinary sum-check still omits the linear coefficient. Changing between the two proof messages requires the matching verifier equation.
Where to inspect the implementation
| Rule | Implementation |
|---|---|
| Equality polynomial definition and tables | akita-algebra/src/eq_poly.rs |
| Split equality state and suffix caches | akita-algebra/src/split_eq.rs |
| Factored prover interface | akita-sumcheck/src/traits.rs |
| Factored round message and proof encoding | akita-sumcheck/src/types.rs |
| Direct prover/verifier functions and normalized claim update | akita-sumcheck/src/single.rs |
For a review, check these facts together:
- The challenge order used by , the data table, and
GruenSplitEqagrees. - The declared degree bounds apply to the inner polynomial , not the product .
- The proof shape fixes the number of rounds and stored coefficients before decoding.
- Prover and verifier use the same and challenge in every update.
- The final comparison uses the normalized oracle value, without an accumulated equality scale.
- Tests compare the split representation with the full equality table, not only with another optimized path.
Equality factoring does not change what the protocol proves. It exposes a factor the verifier already knows, then removes work and proof data that would otherwise repeat that structure.
Extension-opening reduction
An opening claim gives a point and a value , and asks the verifier to check that the committed polynomial evaluates to at . The verifier knows the commitment, not the full polynomial table.
Extension-opening reduction, or EOR, handles a base-field table opened at an extension-field point. It packs several base-field entries into each extension-field entry, then reduces the original opening claim to a claim about that packed table. The number of table entries falls, but the underlying base-field data stays the same.
The main idea is to compare two ways of reading a two-dimensional table. One path evaluates its columns first. The other packs its rows first. A small table of partial evaluations connects the two paths. Sumcheck checks that connection, and Akita's subsequent opening checks bind its result to the committed witness.
This page starts with one polynomial and one opening. The implementation page explains how Akita combines several openings and selects EOR in a recursive schedule.
A small example
Work over , so base-field arithmetic is modulo . Use the quadratic extension with basis . Every extension-field value has two base-field coordinates. These small fields are only for the example, not a secure parameter choice.
Consider a two-variable table . The head bit selects a column and the tail bit selects a row:
| Tail | Head | Head | Pack across the row |
|---|---|---|---|
Packing stores each pair as the two coordinates of one extension-field value. It produces a table with one variable instead of two.
Now open the original table at . Multilinear evaluation uses weights for a bit opened at . Evaluating down the two columns at the tail point gives the column partials
The head point then gives the original opening value
Packing uses the fixed weights , whereas the head evaluation uses . These are different operations. Indeed, evaluating the packed table at the same tail point gives
which is not . The tilde denotes the multilinear polynomial defined by a Boolean table. EOR must prove a relation between these two representations; it cannot simply replace by and keep the opening value.
The general input and packed table
Let have degree over . Fix the canonical -basis used by the field implementation. The basis is public and does not depend on a challenge.
The prover holds an -variable base-field table , where . Split its indices and opening point into a head of length and a tail of length :
The incoming claim is . Both parties know , , and the commitment before EOR begins. Knowing does not mean that the claim is already verified.
For equally sized tuples , define the equality polynomial
Its values at Boolean indices are the interpolation weights. Thus
The prover packs the head entries at each Boolean tail position:
The table has extension-field entries in place of base-field entries. It is a lossless representation of , not a separately chosen witness. Akita uses little-endian Boolean order, so the flat entry at is when the bit strings are read as integers. The prover does not send the full table or in the EOR proof.
Send column partials
The prover first computes one partial for each head index:
It sends these extension-field values. The verifier checks their count and tests whether they recover the incoming opening:
The verifier can perform this check without knowing . But it only checks consistency with . A dishonest prover could choose unrelated partials that pass Equation (4). The rest of EOR must connect these particular partials to the packed witness.
Derive row partials
Both parties decompose each received column partial in the fixed basis:
The index selects a basis coordinate; still selects a head column. They have the same range but different roles. The coefficients form a by table.
For the example, and give
| Basis coordinate | Column | Column | Repack this row |
|---|---|---|---|
In general, repacking the -th row means computing
This basis transpose has no new prover message. The verifier derives every from the received . A row partial is one extension-field value, not a polynomial. Its value is now known, but its claimed relation to the witness remains to be checked.
Build the public factors
To express the row claims in terms of , decompose each tail equality weight in the same basis:
Here is Boolean and extracts coordinate in the fixed basis. Every is a public Boolean table. The verifier can compute its entries from alone, without any witness data. This is why these factors are called transparent.
Substitute Equation (7) into Equation (3). Since , multiplication by scales each basis coordinate without mixing them:
Now repack across :
The relation to be proved is therefore
The verifier derives the left side from the received partials. On the right, the factor is public and the table is the prover's packed witness. For honest partials, the identity follows by exchanging two sums. In the protocol, it is an obligation to check, not an assumption the verifier makes.
The example makes the exchange visible. The tail weights are and , so their coordinate tables are
| Coordinate | ||
|---|---|---|
Consequently,
Taking a coordinate after evaluating the columns gives the same result as using that coordinate of the weights on the packed rows.
Batch the row claims
Rather than prove all row relations separately, the protocol combines them with fresh random weights. After the original claim values and all column partials enter the transcript, it derives a point . Both parties compute
Neither nor is sent. The verifier derives from the received partials and derives from the public tail point and . Equation (9) now gives the single sumcheck claim
For the degree-two example, has one coordinate. The row weights are , giving
The challenge must follow the partials. Otherwise a prover could choose row errors to cancel under already known weights. With the partials fixed first, row errors define a multilinear polynomial in ; a false collection of rows can still pass at an unlucky challenge, but cannot choose its errors after seeing that challenge.
From a public table to a polynomial
Sumcheck evaluates away from the Boolean cube, so it needs polynomials, not just table entries. Write , , and for the multilinear extensions of their respective tables. For example,
The polynomial has coefficients in . The polynomials and have coefficients in . Each has degree at most one in every tail variable. For the example, Equation (12) is just
At an extension-field point , evaluate the multilinear extension of the coordinate table. Do not replace by . Coordinate extraction is only -linear, so it cannot in general move past the extension-field interpolation weights. The verifier computes without materializing the full Boolean table.
Reduce the sum to one point
Define
Each factor is multilinear, so has degree at most two in each variable. Sumcheck reduces Equation (11) over the tail variables. It starts with the known target .
In round , after challenges , the honest prover forms the univariate polynomial
The prover sends the round polynomial in the protocol's compressed encoding. The verifier reconstructs a polynomial of degree at most two and checks . After absorbing that message, the transcript derives , and both parties set . In Akita, challenges come from the shared transcript rather than a separate verifier message; the schedule also specifies transcript grinding.
After rounds, the challenge point is . The prover sends a terminal product claim . The verifier checks and computes the public factor . The remaining obligation is
The sumcheck messages alone do not verify this final witness evaluation. They reduce the original sum claim to Equation (14). If , there are no round messages and is empty; the same final product relation still applies.
Bind the result to the committed witness
Akita keeps and separate. It does not send an independent in the EOR payload, and it does not divide by . The next opening checks must prove Equation (14) for the packed representation of the same incoming committed table. The product relation does not recover an unscaled value when .
For a nonterminal fold, EvaluationTrace supplies a public linear relation
on the fold's opening digits. Akita multiplies its opening weights by
and uses as the target. The fold's source-consistency and
commitment relations connect those digits back to the incoming witness.
Stage 2
checks the resulting relations together.
The terminal path checks the corresponding trace relation directly against
its terminal response and has no Stage-2 sumcheck.
Passing the column check, deriving the rows, and replaying sumcheck are not independent proofs of the original opening. They are successive reductions whose final witness relation must also be checked.
What the prover sends
The following table lists the algebraic data for one opening. The input value may itself be a claim carried from an earlier protocol stage; it is not a new field in the EOR payload.
| Object | Meaning | How the verifier obtains it |
|---|---|---|
| and the commitment | Incoming opening claim | Already available at the EOR boundary |
| Original and packed witness tables | The prover does not send these full tables in EOR | |
| Claimed column partials | Sent by the prover | |
| Coordinates and repacked rows | Derived from the received | |
| Public coordinate tables | Derived from and the fixed basis | |
| Row and sumcheck challenges | Derived from the transcript in order | |
| Batched public factor and its final evaluation | Derived from | |
| Sumcheck input target | Derived from the rows and | |
| Degree-two round polynomials | Sent in compressed form | |
| Claimed final product | Sent by the prover and checked against the sumcheck output |
In particular, a derived value need not be a verified witness value. The verifier knows after reading the partials, but Equation (9) is still a claim about the hidden table .
The message flow is:
Prover Verifier
holds f; derives packed table g knows r, v, commitment
|
+---------------- S_y ------------------> checks recombination to v
derives row_u from S_y
both derive eta after absorbing the partials
both compute c_eta and the public factor A_eta
+------------ round polynomial ---------> checks the round relation
both derive the next rho coordinate repeat for each tail bit
+----------------- h -------------------> checks h = final round claim
computes theta
remaining claim: h = theta * g_tilde(rho)
Akita's opening and commitment checks bind it to the witness
Where Akita uses this reduction
A scheduled fold uses EOR exactly when its opening method is
EvaluationTrace and its claim field is a proper extension of its base
field. A single-field configuration needs no EOR. A
SubringCoefficientPacking fold binds the original extension-valued opening
directly and also omits EOR. See
Fold path and field geometry.
With multiple claims, Akita runs one shared EOR sumcheck and sends one terminal product for each opening. It uses an early set of coefficients inside EOR and a separate set after the fold's opening payload is fixed. Groups retain their own public points and native tail lengths. The multi-group description explains those two batching steps and the common sumcheck domain.
Structure of the transparent factor
The transparent factor has more structure than an arbitrary dense table. Use the coordinate maps from Equation (7) and the weights from Equation (10). Define the base-field-linear batching map by
Split the remaining Boolean variables into a prefix and suffix. The equality product splits as
On Boolean inputs, the EOR factor can then be written as only [E:F]
separable terms:
A direct multiplication-table expansion would expose [E:F]^2 terms. Expanding
only the prefix factor in the fixed basis gives Equation (15).
Equation (15) is first an identity between Boolean tables. During sumcheck, the
coordinate tables on its right must be folded as multilinear polynomials. It
would be incorrect to evaluate the extension-valued prefix at a non-Boolean
challenge and then apply coord_u: the coordinate map is base-field linear,
not extension-field linear.
The production prover currently materializes the dense factor. The separable form instead identifies a future small-space execution strategy; see the roadmap.
Code reference
- Shared tensor algebra
defines the head split, basis packing, column-to-row transpose, and public
factor evaluation. In particular,
tensor_equality_factor_eval_at_pointevaluates Equation (12), not coordinates of an already evaluated equality. - Prover tensor tables build the column partials and the dense factor table from the witness.
- Prover orchestration
absorbs claims and partials before sampling , runs sumcheck, and
records the terminal products. The
proof type
carries
partials,sumcheck, andfinal_claims. - Verifier replay checks the required payload and shape, recombines partials to , and reconstructs the same row claims and public factors. Fold claim preparation applies the factors to the later evaluation-trace weights.
The tensor and sumcheck tests compare partial recombination with direct evaluation, the row claim with the dense witness-factor sum, and the verifier's factor evaluation with the multilinear extension of the factor table. The verifier replay tests also reject changed partials, missing terminal claims, and EOR payloads that do not match the scheduled method. These tests check the implementation's algebra and rejection paths; they do not replace a soundness analysis of the composed protocol.
Polynomial commitments and binding
A polynomial commitment lets a prover fix a polynomial now and prove an evaluation of it later. The verifier receives a short commitment and an opening proof instead of reading the complete polynomial.
Akita's main interface commits to multilinear tables. For example, over , the table
| Value | |
|---|---|
| 1 | |
| 3 | |
| 2 | |
| 4 |
defines the multilinear polynomial . An opening at claims the value . The point need not lie on the Boolean table domain.
The statement and its guarantees
Setup produces public parameters. Commitment maps an admissible table to a public value , together with prover state retained for opening. Opening takes the committed table and a point , and produces a proof for the claimed value . Verification checks
Here includes the public setup and the parameters that determine the table's interpretation. The instance descriptor binds those parameters before challenge generation.
Completeness means that honest commitment and opening computations produce an accepted claim. Akita also has bounded honest-prover searches for fold responses and transcript proof of work. A search can return an exhaustion error instead of a proof. Its probability is a completeness consideration, separate from whether a dishonest proof can be accepted.
Evaluation binding rules out efficiently producing two accepted openings of the same commitment at the same point with different values, except with the allowed failure probability. In the example, accepting both and at would violate binding. Opening the same polynomial at a different point is ordinary use.
Knowledge soundness asks for more. An extractor with the prescribed access to a successful prover should be able to recover a witness explaining its claim, except with a stated knowledge error. An extractor is an algorithm used in the security argument. It is not the ordinary verifier, and the verifier does not reconstruct the full table during each opening.
Hiding asks whether a commitment conceals its contents, and zero knowledge asks whether a proof reveals information beyond its public statement. Neither follows from binding. Akita's current commitment and opening path does not promise either property. See the current privacy boundary.
Why short vectors matter
An Ajtai commitment applies a public matrix to a short vector. In the ring case, let , let , and let have small integer coefficient representatives. Its image is .
If two distinct admitted vectors give the same image, subtract their equations:
If each input has coefficient norm at most , the triangle inequality gives
The analogous statement for Euclidean bounds is . Module-SIS asks for a short nonzero vector in such a matrix kernel. Ordinary linear algebra can find kernel vectors when the matrix has more columns than rows; the hardness requirement is finding one within the specified bound.
This is why an accepted digit range or response norm is part of the binding argument. An equation modulo the field does not by itself certify a small integer representative. The prover's storage type is not a substitute for a verifier-enforced bound either.
Equations (2) and (3) describe the elementary collision argument. A full folding extraction can introduce additional factors from challenges, decomposition, and ring arithmetic. The concrete SIS bounds must account for those factors rather than using as a universal Akita bound.
The two-tier Ajtai commitment
Akita first computes an inner image for each source block. It decomposes those images into short digits and computes the outer image . A standalone commitment then compresses through two more short-input matrix maps to a 128-byte payload.
This creates several binding obligations. If two different sources share a commitment, follow their images through the chain. Where distinct admitted inputs first acquire the same output, their difference gives a short kernel vector for that map. If inner images differ, the outer and compression maps must authenticate them; if an inner image is shared by distinct source digits, the A relation supplies the collision.
D enters during opening. It binds the opening partials through , with its own compression chain when the fold uses compressed payloads. The fold's consistency relation connects these partials to the same source used by A. The scalar opening relation then connects them to .
Later recursive folds can use raw B and D images. That removes their payload compression maps but preserves the A, B, D, consistency, and scalar-opening obligations. The terminal uses a direct A and consistency check instead of creating another outer commitment. The complete data path is described in setup and commitment and recursion.
Ring dimension, module rank, input width, and accepted norm therefore matter for each matrix actually used. Akita records these in the selected schedule and validates them when expanding it. The coefficient Linf and Euclidean L2 routes use different SIS tables because they certify different norms. Security model owns the concrete sizing policy.
Coordinate-wise special soundness
Folding compresses many source blocks into a response . One response alone cannot recover all the . Extraction instead considers accepting answers to related challenges while keeping the earlier messages fixed.
For intuition, suppose two answers differ only at coordinate . Honest responses satisfy
If the challenge difference is a unit, division recovers . In a ring, a nonzero difference need not be a unit. The full ring argument must establish the unit property and control the bounds needed for a matrix-collision reduction. Equation (4) illustrates the coordinate fork; it does not by itself establish those properties.
Coordinate-wise special soundness, or CWSS, describes the accepting transcripts needed for this extraction. At one fold, take the original selected accepting run as the central child. For each coordinate, obtain another accepting child that changes only that coordinate. All children share the prover messages sent before the challenge, and each has its own accepting proof for the later checks. Repeating this construction at every fold produces an accepting transcript tree.
Akita's sampler exposes each coordinate separately. At fold level ,
commitment group has
coordinates. A coordinate is one sparse ring element for a claim and source
block. The sampler squeezes
one 32-byte group root, then uses
SHAKE256(root || little_endian_u64(index)), with
index = claim * num_live_blocks + block. The group payload binds the method,
dimension, challenge family, group index, and counts. In the ideal-oracle
model, each indexed input has its own random answer. The extractor can
therefore change one coordinate while keeping the others fixed.
There are two opening methods. Evaluation trace uses the scheduled challenge ring and permits coefficient-Linf or selective-L2 response security. Subring coefficient packing samples in the specified challenge subring and requires the Linf route. Selective L2 currently requires one scalar group; the terminal has one evaluation-trace group with one claim. Packing also has a separate consistency polynomial check of degree at most , where is the challenge-subring dimension. Its field error enters the relation-check ledger.
Let be the support after fixed sampler filters. For a shell in dimension with coefficients of magnitude one and of magnitude two, its unfiltered cardinality is . The production shell ladder has at least 128 support bits per coordinate. Selective L2 at D64 and D128 uses a fixed operator-norm predicate; its certified accepted subset also retains at least 128 support bits. The grinding specification records the exact families. The accepted-support bound is the denominator used below, including for filtered samplers.
Binary CWSS uses a common prechallenge prefix and, for each coordinate, a pair of accepting children that agree everywhere else. Each child has its own complete accepting subtree for the later ring, range, norm, relation, and recursive checks. Later challenges may differ. These strong checks recover exact native-ring identities and verifier-certified response bounds below each child. If the children open a common commitment path differently, the commitment maps give a scheduled matrix collision. Otherwise, subtraction cancels every unchanged fold term. The production LS18 check makes the remaining nonzero challenge difference a unit in both opening methods, so division recovers that coordinate's weak opening. The extractor accepts any source opening that satisfies the verified relations. To bound a collision, it cross-multiplies accepted responses and challenge differences before centering the resulting kernel vector.
The terminal's direct relations authenticate its incoming opening. Applying the preceding step backward through the folds extracts the root openings or a short collision in a scheduled matrix view. A fold with coordinates in group requires children. These factors multiply across folds and with the other challenge stages. The grinding specification gives the extraction and collision steps in more detail.
Fiat-Shamir queries and fold nonces
Fiat–Shamir derives each verifier challenge from the public statement and the proof prefix through a random oracle. A dishonest prover can try several proof prefixes, including different fold-response nonces, before submitting one proof. The security bound therefore counts the oracle inputs that the prover actually explores.
What one coordinate query means
A fold coordinate address is the pair (group root, claim-major index).
Requesting any bytes from its indexed SHAKE256 stream touches that address.
Further reads from the same stream use the same answer. A different root or
index gives a different address. The 32-byte group root is also an oracle
output; it belongs in the total query budget. Distinct transcript contexts
that produce the same root are covered by the separate root-collision term.
For each possible address , let when the original dishonest prover touches it during any attempted proof, and let otherwise. Let when verification of the final submitted proof first needs that address and the prover did not touch it. Thus and mark disjoint sets. The extractor's replay queries affect its running time; the security charge uses the original prover's queries.
bounds in every execution of the dishonest prover. is the maximum number of previously untouched addresses in one final proof under the selected schedule. One final proof uses at most one address for each scheduled fold coordinate, so
For example, suppose the final proof has three fold coordinates. If the prover has already read two streams for that proof, final verification completes one address: those three addresses contribute two to the observed query count and one to the completion count. Reading all three coordinates under a second candidate root adds three more query addresses.
The fold bound
Let be the set of possible values at address after the sampler's fixed filters, and let be the smallest such set in the schedule. Fixed operator filtering changes this set; the source-dependent test that a fold response fits its bounds changes which proof the prover submits and is charged through its oracle queries. The indexed streams are uniform on their respective accepted sets in the ideal-oracle model, conditional on sampler success.
The fold extraction argument gives
The expectation covers the dishonest prover's choices and the random oracle. To understand the one-value numerator, keep the original selected accepting run, fix every other oracle answer, and vary the answer at one selected coordinate address. Two suitable accepted values at that address provide the coordinate fork used by the accepting-tree extractor. The remaining matching-input failure can therefore occupy at most one accepted value at that address. An address contributes only when the original prover touched it or final verification completes it. Applying this charge through the tree gives (6). The grinding specification states the exact conditional sampling and tree argument.
Every production accepted coordinate set contains at least values. Equation (6) therefore assigns at most to each charged fold address with zero additional fold proof of work. A 12-bit fold-response nonce lets the prover try more prefixes; the coordinate streams read during those trials increase . This accounts for that choice directly.
From the fold bound to a security claim
For a particular attacker budget, substitute its maximum number of distinct coordinate addresses and the schedule's verifier-completion bound into (6). For example, gives a fold term of at most when . An aggregate 128-bit target requires enough support margin to cover the declared query and completion counts.
The full knowledge-soundness calculation also includes the other challenge checks, setup distance, compressed-root collisions, and scheduled matrix-collision advantages. Each field challenge must use the loss of its actual position in the complete extraction tree when pricing the full calculation. The current grinding plan prices its typed local field checks; a complete tree calculation supplies their combined extraction debits. The fold tree itself contributes to extractor cost. The complete tree, including its other challenge stages, must have polynomial size in the declared instance length and security parameter for an expected polynomial-time knowledge extractor.
This analysis is in the classical random-oracle model. The grinding specification gives the detailed reduction ledger and implementation evidence.
Honest search measures how often the response fits the scheduled cap. Under an independent-trial model with per-trial acceptance probability , the chance of exhausting attempts is . This is an honest-proving completeness measure. Any estimate of is tied to its measured source and schedule.
A concrete security claim combines matrix hardness estimates with the folding, ring-relation, sumcheck, and Fiat–Shamir bounds.
Implementation map
crates/akita-params/src/sis/owns matrix and norm security parameters. Schedule validation checks the selected geometry against those parameters.crates/akita-prover/src/protocol/fold_grind.rsperforms bounded honest response search.crates/akita-challenges/src/sampler/xof.rsgives sparse challenge coordinates distinct oracle inputs.crates/akita-types/src/instance_descriptor/binds schedule identity and the protocol-wide grinding contract.crates/akita-verifier/src/terminal/direct.rschecks the final response norm and direct relations.crates/akita-pcs/tests/fold_linf.rsandcrates/akita-pcs/tests/transcript_hardening.rsprovide regression checks for nonce replay, bounds, and transcript tampering. Such tests support the correspondence with the implementation; they do not prove extraction.
Glossary and notation
This page is a quick reference for terms and symbols used throughout the Akita Book. Individual chapters introduce each idea in more detail.
Glossary
| Term | Meaning |
|---|---|
| Polynomial commitment scheme (PCS) | A protocol that commits to a polynomial and later proves a claimed evaluation without sending the whole polynomial. |
| Multilinear polynomial | A polynomial that has degree at most one in each variable. Its values on the Boolean cube determine it everywhere. |
| Evaluation table | The values of a multilinear polynomial at all Boolean inputs. A polynomial in variables has a table of length . |
| Commitment | A short public value that binds the polynomial for later opening checks. This does not promise hiding; see Akita's current privacy boundary. |
| Opening | A proof that a committed polynomial evaluates to a claimed value at a specified point. |
| Opening claim | The polynomial identity being proved: a commitment, an opening point, and the claimed value. |
| Commitment group | One or more related commitments that are opened together under one generated schedule. |
| Precommitted group | A commitment produced earlier and carried into a later grouped opening. Its profile is fixed when the commitment is created. |
| Fold | One step that replaces a large opening relation with a smaller one while preserving the claim the verifier must check. |
| Root fold | The first fold. It starts from the user's polynomial commitments and opening claims. |
| Recursive fold | An intermediate fold that consumes the relation produced by the preceding fold. A schedule may contain none. |
| Terminal fold | The final step, where the remaining witness is small enough to reveal and check directly. |
| Generated schedule | A precomputed choice of fold dimensions, bounds, opening methods, and proof layout for one supported request shape. |
| Catalog row | The generated record selected for a particular configuration and group shape. The prover and verifier read the same row. |
| Proof shape | The exact number, order, dimensions, and byte layout of every proof component required by a schedule. |
| Public setup | Public matrices and prepared data used to commit, prove, and verify. Akita does not require a secret trapdoor. |
| Transcript | The ordered record of public inputs and proof messages from which Fiat-Shamir challenges are derived. |
| Base field | The field that stores committed coefficients and supports the lattice relation. |
| Extension field | A larger field used for opening points, claimed evaluations, and transcript challenges in some configurations. |
| Cyclotomic ring | The quotient ring in which Akita's lattice commitments and fast polynomial arithmetic operate. |
| Dense polynomial | A polynomial whose table positions may each contain an arbitrary field element. |
| One-hot polynomial | A polynomial whose table has at most one 1 in each consecutive chunk of onehot_k entries; all other entries are zero. An all-zero chunk is allowed. Akita can use smaller schedules for this structure. |
| Gadget decomposition | Writing a field or ring value as a short vector of bounded signed digits in a power-of-two base. |
| Module-SIS | The lattice assumption used to bind Akita commitments. Informally, it says that finding a short nonzero relation among the public commitment columns is hard. |
| Sum-check | An interactive reduction that turns a sum over a Boolean cube into one polynomial evaluation at a random point. |
| Extension-opening reduction | The bridge from a base-field polynomial opened at an extension-field point to a packed extension-field polynomial with fewer variables. |
| Ring switching | Akita's lattice step that lifts a relation from a quotient ring to an integer polynomial relation with an explicit quotient. It is distinct from extension-opening reduction. |
| Setup offloading | Carrying a committed setup prefix into a later fold so that recursive verification does less setup work directly. |
Scalar and grouped catalog rows
A trusted external catalog ships one row for each supported request shape.
- A scalar row describes a polynomial group opened without precommitted groups. An independent commitment always uses this row, including a commitment that will later be supplied as a precommitted group.
- A grouped row describes a final group together with an exact ordered prefix of precommitted group profiles. The complete batch is opened under this row.
Each precommitted descriptor in a grouped row must equal the scalar-row profile
under which that commitment was produced. The external-catalog audit test
every_grouped_artifact_precommit_has_a_shipped_scalar_producer enforces this
invariant.
Notation
| Symbol | Meaning |
|---|---|
| The base field. | |
| The extension field used for public challenges and evaluations. It may equal . | |
| The extension degree, or the number of base-field coordinates in one extension-field value. | |
| The prime modulus of the field in the surrounding chapter. | |
| A cyclotomic polynomial ring with coefficients reduced modulo . | |
| The number of variables in a multilinear polynomial. Its evaluation table has entries. | |
| A public opening point. | |
| A claimed polynomial value at the opening point. | |
| A power-of-two gadget-decomposition base. | |
| The base-two logarithm of the decomposition base, called the basis exponent in code. | |
| The number of signed digits in a gadget decomposition. | |
| The signed digit at position . | |
| The multilinear equality polynomial. On Boolean inputs, it is one at and zero elsewhere. | |
| A random point produced by a sum-check transcript. |
Some implementation chapters use short names such as A, B, and D for matrix roles. Those letters identify protocol roles, not universal mathematical symbols. Each chapter defines them before use.
Spec index
This index names the specifications that still define current behavior or
unresolved work. Shipped and superseded records live in
specs/archive/README.md. The lifecycle
policy and the checker use the same live set in
specs/PRUNING.md and
scripts/check-spec-references.sh.
Live specifications
| Spec | Status | Why it remains live |
|---|---|---|
akita-compute-backend-metal | active | Metal and hybrid backend work remains open. |
composable-commitment-execution | active | Defines the current commitment source, backend composition, retained-state, and routing contracts while proving backend work remains open. |
quotient-free-tail-ring-relations | active | Defines reduced evaluation and its bounded quotient-free tail cutover. |
quotient-free-tail-ring-relations-implementation | active | Defines the implementation architecture and acceptance contract for the quotient-free tail cutover. |
dyadic-chunk-partition | implemented | Defines the current witness chunk partition contract. |
family-agnostic-cpu-backend | active | Defines producer-catalog and proving-catalog ownership for one (F, E) backend, producer-contract provenance, and slot-keyed prefix persistence. |
external-schedule-catalog-ownership | active | Owns the in-flight cut from compiled schedule rows to explicitly supplied full-catalog artifacts. |
guided-schedule-adaptation | active | Defines bounded offline adaptation from trusted scalar rows to exact grouped rows. |
flat-public-matrix-and-exact-ntt-cache | implemented | Load-bearing setup layout with follow-up provenance and artifact work. |
fold-linf-rejection | implemented | Its sizing formula is used by the SIS cap implementation. |
heterogeneous-group-source-contracts | implemented | Defines current source-free group and fold-admission rules. |
jolt-field-unification | active | Tracks the in-flight cutover to one shared Akita/Jolt field stack. |
large-digit-ntt-infrastructure | implemented | Load-bearing large-digit NTT and terminal verification contract. |
packed-sumcheck | approved | Approved packed EOR and sum-check implementation; earlier Stage 1 and Stage 2 prerequisite gates are complete. |
role-native-projected-digit-layout | implemented | Normative witness and verifier layout source. |
runtime-ring-cutover | implemented | Normative runtime ring contract cited by the architecture chapter. |
selective-l2-fold-security-sizing | implemented | Current security sizing source; deferred alternatives remain recorded. |
setup-offloading-planner | implemented | Current recursive setup selection policy and external artifact contract. |
sis-quantum128-scalar-n-table | implemented | Current 128-bit SIS security policy source. |
structured-e-term | implemented | Current structured verifier E-term contract. |
subring-coefficient-packing | active | Defines packing relations, indexed fold challenges, and planner contracts. Its review record reports all three blockers repaired. |
transcript-grinding | implemented | Defines the current proof-of-work and fold-response grinding policy. |
grinding-nonce-encoding | active | Explains current inline-LEB128 nonces and compares them with the historical packed representation. |
Archived records
The archive contains the historical design record for shipped work and the superseded alternatives that explain why the live contracts have their current shape. Update the owning Book chapter for current narrative text. Do not use an archived record as a source for new behavior.
Maintenance
When a PR changes a specification, update its status and links in the same PR.
When a specification is shipped and its durable content is in the Book, move it
to the archive and add an entry to the archive index. Run
scripts/check-spec-references.sh --all during quarterly cleanup to find stale
non-archive references.
References
These public references provide background for the ideas used by Akita. They are grouped by the part of the Book they help explain. The repository's code, live specifications, generated tables, and tests define the behavior of the current implementation.
Lattice commitments and folding
- LaBRADOR: Compact Proofs for R1CS from Module-SIS develops compact lattice-based arguments and commitment techniques from Module-SIS.
- Greyhound: Fast Polynomial Commitments from Lattices develops a lattice-based polynomial commitment scheme with an emphasis on prover efficiency.
- Hachi: Efficient Lattice-Based Multilinear Polynomial Commitments develops the lattice-folding lineage most directly related to Akita's ring relations.
- Practical Product Proofs for Lattice Commitments gives background on proving multiplicative relations over lattice commitments.
Multilinear polynomials and sum-check
- Algebraic Methods for Interactive Proof Systems introduces the sum-check protocol used to reduce a Boolean-cube sum to a single evaluation.
- Some Improvements for the PIOP for ZeroCheck explains equality-polynomial factoring techniques related to Akita's equality-factored sum-check.
Extension fields and packed openings
- Succinct Arguments over Towers of Binary Fields develops packed multilinear techniques over extension fields and provides useful background for extension-opening reduction.
Post-quantum lattice standards
- NIST FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism standardizes a module-lattice key-encapsulation mechanism.
- NIST FIPS 204: Module-Lattice-Based Digital Signature Standard standardizes a module-lattice digital signature scheme.
Akita is a polynomial commitment scheme, not an implementation of either NIST standard. These standards are relevant because they show how structured lattice assumptions are being deployed in production cryptography.
Public implementations
The Why lattices? chapter links to public implementations of LaBRADOR, LaZer, RoKoko, and Jindo. They are useful points of comparison for repository structure, portability, proof encoding, and integration readiness.
Roadmap
Status: index of remaining implementation and integration work.
This section tracks capabilities that are not part of the current production implementation. Compute backends tracks the active Metal work. Zero knowledge states the current privacy boundary and the requirements for any future implementation.
Implemented work belongs under How it works. Setup offloading explains the recursive setup path. Prover optimizations covers the current commitment tiling, matrix streaming, and streaming suffix tensor inputs.
Small-space extension-opening prover
The production EOR prover materializes one packed witness table per claim and one transparent factor table per group. It reuses the group factor and avoids expanding smaller groups to the maximum arity, but its largest tables are still linear in the native EOR domain. The implementation chapter documents that path.
The separable representation of the transparent factor suggests a different prover organization. Partition an EOR domain of size into stages. At each stage, fold the small basis-coordinate prefix tables and accumulate suffix contractions against the current witness source. A fully streamed form could read the original base-field coordinate tables directly instead of first retaining the packed extension-field table.
For extension degree , this organization targets working memory and field operations.
It would change only how the prover supplies the existing degree-two sumcheck
terms. The transcript and verifier need not change. No current protocol path
implements this staged construction, and there is no active PR for it. The
closed PR #398 and the
records in specs/archive/2026-Q3/eor-streamed-prover.md and
specs/archive/2026-Q3/eor-sumcheck-prover-acceleration.md are historical
experiments, not the production design.
Recursion in production
Open follow-ups for running the verifier inside Jolt at scale: cycle-count results, remaining glue work, and the prerequisites tracked in the recursion sub-workspace.
Sources to fold in
profile/akita-recursion/README.md(open follow-ups, cycle results).
Zero knowledge
Status: Akita does not currently provide zero knowledge and has no
zkCargo feature.
Zero knowledge means that a verifier learns no private witness information beyond what follows from the public statement and whether the proof is valid. The current Akita proof does not make that promise. It proves that an opening is consistent with a commitment, but its proof messages may reveal information about the committed values.
Applications must therefore treat the current PCS as transparent. They must not place a private witness in an Akita commitment and assume that an opening hides it. A host proof system may provide privacy through a separate construction, but that property does not come from the current Akita API.
Why this requires an end to end design
Hiding only the initial commitment would not be enough. An Akita proof exposes messages at several later points:
- each sumcheck sends round polynomials derived from the witness;
- each fold commits to values derived from the preceding witness; and
- terminal verification receives the final short witness in clear form.
A complete zero knowledge construction must hide every one of these messages while preserving the same opening claim. It must also show that the masks used at one level remain valid after folding and do not break the norm bounds behind Module-SIS security.
Historical implementation work
An earlier experiment implemented part of commitment rerandomization and part
of sumcheck masking. It did not hide the complete proof, so it was removed from
the production code. The historical source remains on the zk-wip branch and
the zk-prefix-snapshot-2026-06 tag.
That experiment must not be restored as a partial zk mode. A feature named
zero knowledge must protect the complete proof or clearly be an internal test
of one component.
Requirements for future work
There is no approved implementation plan at present. A new proposal must cover the following boundaries before code is treated as a production feature:
- It must define what is public and what remains private.
- It must account for every transcript message from the first commitment to the terminal check.
- It must preserve the range and norm bounds used by the binding proof.
- It must specify how the prover samples masks and what happens when sampling rejects.
- It must give the verifier one complete acceptance rule and reject malformed hiding data without panicking.
- It must include tests that compare the hidden and transparent statements and show that no partial mode can be selected by mistake.
Host integration is a separate layer. If a zkVM combines Akita with its own privacy protocol, that integration must document which component hides each message and which public values cross the boundary.
Compute backends (Metal/GPU)
Status: stub. Part of the initial Akita Book scaffold.
The CPU cutover has landed; the open work is a Metal (and broader GPU) backend behind the explicit compute-operation traits, plus hybrid scheduling.
Sources to fold in
specs/akita-compute-backend-metal.md(Metal tail)docs/compute-backends.md(current boundary)