Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

OperationWhat it does
SetupCreates the public information needed by commitments and proofs
CommitFixes one or more polynomials and produces a compact public commitment
ProveProduces evidence for claimed evaluations of the committed polynomials
VerifyChecks 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.

ApproachMain advantageMain cost
Elliptic curves and pairingsVery small proofs and fast verificationThe security assumptions are not post-quantum, and some schemes require a trusted setup
Hash functionsPost-quantum security and transparent setupProofs often contain many hash tree paths, which increases proof size and data movement
Structured latticesPost-quantum security with useful algebraic structureParameters, 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 levelField values entering the level
L0268,435,456
L155,332,544
L23,892,032
L31,064,256
L4488,384
L5255,488
L6, terminal128,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 partWhat it containsSize
The folded witness response, 16,384 coefficients stored with a compact integer encoding called Golomb coding20,334 bytes
The 512 opening values needed by the final check8,192 bytes
The 1,536 inner commitment values needed by the final check24,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:

GoalContinue with
Run Akita or integrate the PCSUsage
Learn the mathematical ideas from the beginningFoundations
Follow the protocol and implementationHow it works
Review the assumptions and verifier boundaryReviewing and auditing Akita
See planned work rather than current behaviorRoadmap

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:

  1. Canonical decoding and size limits.
  2. Configuration and generated schedule admission.
  3. Setup capacity and setup identity.
  4. Opening claim shape and group order.
  5. Transcript binding before each challenge.
  6. Response bounds and relation checks.
  7. 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.

CrateReview role
external jolt-field and akita-algebraField, ring, transform, and polynomial arithmetic
akita-serializationCanonical encoding and checked decoding
akita-transcript and akita-challengesInstance binding and challenge derivation
akita-sumcheckShared sumcheck proof types and drivers
akita-typesPublic proof, setup, schedule, commitment, and claim shapes
akita-plannerOffline schedule search and cost evaluation
akita-schedulesExternal schedule artifact decoding, admission, and lookup
akita-configConcrete policy and schedule admission
akita-setupPublic setup construction and setup artifacts
akita-proverCommitment and proof generation
akita-verifierProof replay and rejection of invalid statements
akita-pcsEnd 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:

  1. The scalar or mathematical reference operation.
  2. The accepted input range and intermediate bound.
  3. The runtime feature check that selects the kernel.
  4. Differential tests over boundary values and random inputs.
  5. 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.

SourceWhat it establishes
Current codeRuntime behavior and enforced API boundaries
External schedule artifactsConcrete schedules and parameters admitted by normal builds
Live specificationsAccepted designs that still contain details not folded into the Book
The BookThe maintained explanation of current behavior
TestsEvidence for selected valid cases, rejection paths, and cross implementation agreement
Archived specificationsDesign 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 goalStart withContinue with
Binding and security parametersPolynomial commitments and bindingSecurity model and generated schedules
Transcript soundnessTranscript and instance bindingTranscript labels, logging tests, and proof replay
Malformed input safetyVerificationSerialization, checked allocation, and rejection tests
Setup correctnessSetup and commitmentSetup capacity, persistence, and setup offloading
Arithmetic correctnessNTT, CRT, and fast ring arithmeticScalar references, vector kernels, and differential tests
Host integrationUsageVerifier 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.

OperationWhat the application suppliesWhat Akita returns
SetupA configuration and maximum workload sizePublic setup data and reusable prover state
CommitOne or more polynomial tablesA public commitment and private prover data
ProveThe committed tables, opening points, and claimed valuesOne batched opening proof
VerifyPublic setup, commitments, claims, and proof bytesSuccess 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 toRead
Run one complete proofYour first proof
Pick a field and input representationChoosing a configuration
Integrate commitment, proving, and verificationIntegrating the PCS
Carry only verification into another environmentVerifier only integration
Choose Cargo featuresFeature flags
Measure time, memory, and proof sizeProfiling
Diagnose a failed runTroubleshooting
Add Akita to another proof systemIntegrating with a proof system
Verify Akita inside a zkVMJolt 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.

CrateRole
akita-pcsComplete setup, commitment, proving, and verification interface
akita-configProduction configurations and trusted artifact validation
akita-schedulesExternal artifact decoding, row audit, and owned catalog lookup
akita-proverPolynomial representations, prepared compute state, and prover kernels
akita-verifierVerification without prover polynomial backends or planner search
akita-typesProofs, commitments, claims, schedules, and setup types shared across the boundary
akita-transcriptThe 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_group is public. The verifier receives it.
  • private_handle retains 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.

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.

FamilyCommitment fieldOpening fieldCommon use
fp32A 32 bit prime fieldA degree 4 extensionHosts built around small prime fields
fp64A 64 bit prime fieldA degree 2 extensionHosts that want 64 bit base arithmetic
fp128A 128 bit prime fieldThe same fieldHosts 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.

RepresentationUse it whenMain benefit
DenseEntries may be arbitrary field elementsGeneral purpose commitment path
OneHotEach fixed size chunk contains one selected positionPreserves the compact source and skips work for zero entries
DenseBoundedEvery centered coefficient fits the declared signed boundUses 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 dataStarting configuration
Arbitrary values in the fp128 fieldfp128::Dense
One selected entry in each fixed size chunkfp128::OneHot
Values known to fit the full u64 rangefp128::DenseBounded
A host using a small prime fieldThe matching fp32 or fp64 family
A verifier that must avoid a large direct setup scanA 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:

  1. Choose a configuration for the host field and polynomial representation.
  2. Load and validate the approved external schedule artifact.
  3. Build prover setup for the largest supported workload from that catalog.
  4. Prepare the compute backend and keep it warm across proofs.
  5. Commit to each polynomial group and retain its private hint.
  6. Assemble the ordered opening claims for one proof.
  7. Let the catalog select the exact trusted row for that batch.
  8. Produce and encode the proof.
  9. Send the catalog identity, public statement, proof, and verifier setup.
  10. 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.

DataOwnerPurpose
Original polynomialsProverSource data for commitment and opening
Commitment hintsProverPrivate data that connects each polynomial group to its commitment
Prepared compute stateProverReusable transforms and backend resources
Trusted schedule catalogBothApproved external parameters used by setup, proving, and verification
Verifier setupPublicPublic matrix data and setup prefix commitments needed by verification
CommitmentsPublicValues that fix the committed polynomial groups
Opening points and valuesPublicThe claims being proved
Schedule selectionPublicIdentity of the approved catalog row used by the batch
Proof bytesPublicEncoded 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

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

ObjectWhat it meansCan local copies differ?
AkitaSetupSeedIdentity of the deterministic public matrix streamNo
Prover setup capacityHow much of that stream the prover materializedYes, if every proof requirement is covered
Setup prefix registryPublic commitments used by recursive setup offloadingIt must cover the same supported schedules
Prepared backend stateLocal transformed matrix prefixes and compute resourcesYes

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:

FieldPurpose
Protocol revisionPins the Akita proof format and transcript schedule
Configuration identitySelects the field policy and expected catalog family
Catalog identity or storage referenceAuthenticates the external schedule artifact supplied to the verifier
Verifier setup identity or packageSupplies the public matrix data needed for replay
Schedule selectionNames one exact approved catalog row
Ordered commitmentsFixes every polynomial group
Ordered opening pointsStates where each group is opened
Ordered claimed valuesStates one value for each committed polynomial
Proof bytesCarries 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 AkitaVerifierSetup for 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:

  1. Choose the feature set and load approved catalog bytes from normal storage.
  2. Run a complete proof workload and inspect time, memory, and proof size.
  3. 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

FeatureWhat it provides
parallelRayon execution across field arithmetic, setup, proving, sumcheck, and verification
transcript-blake2bThe 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.

FeatureBackend
transcript-blake2bBlake2b based Spongefish transcript with SHA3 support
transcript-keccakKeccak 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

FeaturePurpose
logging-transcriptRecords transcript schedule events and checks that wire values are absorbed before challenges
response-model-diagnosticsMeasures 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:

PhaseWork included
Statement preparationDeterministic witness, opening point, and expected value generation
Setup and preparationPublic setup construction and exact retained NTT prewarming
CommitCommitment to the source polynomial groups
ProveComplete opening proof generation
EncodeCompressed proof serialization and size accounting
VerifyReplay with the configured multi threaded verifier pool
Verify with one threadReplay 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

VariableDefaultMeaning
AKITA_MODEonehot_fp128Configuration and source representation
AKITA_NUM_VARS32Number of multilinear variables; use 36 for parity measurements
AKITA_NUM_POLYS1Number of polynomials in the final group
AKITA_PROFILE_PROVE_THREADSRayon defaultProver worker count
AKITA_PROFILE_VERIFY_THREADSProver countVerifier worker count
RAYON_NUM_THREADSRayon defaultFallback 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.

VariableDefaultPurpose
AKITA_PROFILE_TRACE1Write a Chrome and Perfetto trace
AKITA_PROFILE_MONITOR1 when tracingRecord process CPU, host CPU, and memory counters
AKITA_PROFILE_MONITOR_INTERVAL_MS100Resource sampling interval in milliseconds
AKITA_PROFILE_LOGtraceConsole tracing filter
AKITA_PROFILE_ANSI1Colored terminal logs
AKITA_PROFILE_SPAN_CLOSES1Print 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

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

CasePolynomial groupsSetup path
dense_fp321 at nv30Direct
onehot_fp321 at nv34Direct
dense_fp641 at nv29Direct
onehot_fp641 at nv35Direct
dense_fp1281 at nv28Direct
onehot_fp1281 at nv36Direct and recursive
onehot_fp128_multi_group1 at nv16 + 1 at nv16 + 2 at nv34Direct
onehot_fp128_multi_group_recursive1 at nv16 + 1 at nv16 + 2 at nv34Recursive
onehot_fp128_multi_group_recursive_multi_chunk_w8r21 at nv16 + 1 at nv16 + 2 at nv32Recursive
onehot_fp128_multi_chunk_w2r21 at nv32Direct
onehot_fp128_multi_chunk_w4r21 at nv32Direct
onehot_fp128_multi_chunk_w8r21 at nv32Direct

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:

  1. Generate deterministic source data, opening points, and expected values.
  2. Build setup and prepare retained NTT requirements.
  3. Commit to every polynomial group.
  4. Produce and serialize one complete opening proof.
  5. Check the reported proof size.
  6. Build verifier setup.
  7. Verify with the configured worker pool.
  8. 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:

FileUse
summary.jsonComplete machine readable result
summary.csvFlat data for analysis tools
report.mdDetailed human readable report
Pull request commentCompact 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:

  1. Confirm that the application loaded the intended family artifact and that its catalog identity matches the setup or preprocessing package.
  2. Confirm that the chosen preset supports the requested polynomial arity, group shape, and opening method.
  3. For a recursive grouped opening, commit each precommitted group with the base configuration. Use the recursive configuration for the final grouped commitment and proof.
  4. 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:

  1. If LOCALAPPDATA is set, use $LOCALAPPDATA/akita.
  2. Otherwise, if HOME/Library/Caches exists, use $HOME/Library/Caches/akita.
  3. Otherwise, if HOME is 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:

ValueMeaning
0Akita verification succeeded
1Input decoding or statement construction failed
2The 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 concernAdapter decisionAkita input
Which values are committedPreserve the host's canonical orderDense or one hot polynomial sources
Which field holds those valuesSelect the matching Akita configurationCommitmentConfig
Which claims belong togetherGroup polynomials by arity and opening pointOpeningClaims
Which public statement is provedPreserve commitments, points, values, and group orderGroupBatchStatement
Which protocol session owns the proofChoose stable versioned session bytes&[u8] session
What crosses the prover boundaryDefine a versioned public bundleSetup, 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:

  1. Its field.
  2. Its number of variables.
  3. Its table representation.
  4. The point where the host protocol opens it.
  5. 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 placementTypical use
In the host processCheck locally generated proofs and network requests
In a dedicated serviceKeep proving and verification deployments separate
In a zkVM guestProve that the Akita verifier accepted a proof
In another recursive circuitCompress 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:

  1. Compare host and Akita field conversions in both directions.
  2. Compare each claimed value with an independent host evaluation.
  3. Round trip the complete public artifact through serialization.
  4. Accept a valid proof through the final verifier entry point.
  5. Reject changed commitments, points, values, schedules, and proof bytes.
  6. 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.

CrateRuns whereResponsibility
artifactNative hostCreates a real Akita commitment, opening proof, and verifier bundle
glueHost and guestDefines the bounded AkitaJoltInputs wire format
guestJolt RISC-V guestDecodes the bundle and calls AkitaVerifier::batched_verify
hostNative hostCompiles 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:

MarkerWork measured
deserialize_inputDecode and validate the verifier bundle
prepare_verifierAdmit the selected row and install or prepare its terminal matrix
akita_verifyBuild 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:

ValueMeaning
0Akita verification succeeded
1Input decoding or statement construction failed
2The 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:

  1. Run the recursion workspace tests and release build.
  2. Generate a fresh artifact and confirm native verification.
  3. Run --trace-only and compare the three cycle markers.
  4. Run the full Jolt proof at a known arity.
  5. 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.

  1. Resolve the schedule. The selected CommitmentConfig maps the workload shape to one generated schedule row. That row fixes every fold, matrix dimension, decomposition basis, opening method, and terminal profile.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.

ChoiceWhat changesWhere to read
Coefficient packing or evaluation traceHow an extension-valued opening is represented in the fold relationFold path and field geometry
Raw or compressed commitment payloadWhich commitment values appear on the wire and which extra physical rows are provedRaw and compressed realizations
Direct or offloaded setup contributionWhether the verifier scans setup now or a later fold authenticates a prepared setup prefixSetup offloading
Coefficient or Euclidean response boundWhich range and norm checks certify the folded responseSecurity model and Sum-check stages
Dense or one-hot sourceHow the prover computes the commitment and source operationsSetup 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:

  1. Architecture overview for crate ownership and the public commit, prove, and verify lifecycle.
  2. Configuration and planning for the generated schedule and the difference between offline search and runtime resolution.
  3. Setup and commitment for the public matrices and Ajtai commitment.
  4. The proving protocol for one fold from input claim to successor witness.
  5. 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

ChapterMain question
Architecture overviewWhich crate owns each concept, and how do the public calls flow through them?
Configuration and planningHow does one public workload select an exact generated schedule?
Setup and commitmentHow do public matrices bind a polynomial group?
Transcript and instance bindingWhich public facts are absorbed before each Fiat-Shamir challenge?
The proving protocolHow does one nonterminal fold create and authenticate its successor witness?
The distributed proverWhich fold computations can remain local to independent machines?
Recursion and proof shapeHow are root, recursive, and terminal records connected?
Setup offloadingHow can a prepared setup commitment replace a large online verifier scan?
VerificationHow does the verifier replay every level and reject malformed input without panicking?
Security modelWhich assumptions, norm regimes, and generated bounds support acceptance?
OptimizationsHow 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.

CrateRole
akita-errorShared 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-serializationSerialization, validation, and compression traits
akita-algebraModules, vectors, NTTs, cyclotomic rings, sparse challenges, polynomials
akita-transcriptSpongefish-backed Fiat-Shamir transcript, descriptor preamble, logging checks
akita-challengesFiat-Shamir challenge sampling helpers
akita-sumcheckSumcheck proofs, drivers, compact folding, batching, accumulation
akita-paramsParameter geometry, sizing, SIS tables, schedules, compression plans, witness layout, dispatch, and grinding plans
akita-typesProof, setup, and claim wire values, shared protocol math, and native transcript replay
akita-plannerCfg-free offline schedule search and artifact emission
akita-schedulesVersioned schedule artifacts, semantic row audit, and validated owned catalogs
akita-configRuntime presets, the CommitmentConfig trait, trusted artifact loading, policy_of::<Cfg>(chunking), and transcript binding
akita-setupConfig-backed setup construction and optional setup cache
akita-verifierVerifier replay without prover-only polynomial backends; directly <Cfg>-generic
akita-proverProtocol sequencing, public geometry checks, proof assembly, opaque operation contracts
akita-cpu-backendBackend-owned sources, commitment and witness arithmetic, prepared setup resources, caches
akita-pcsUmbrella 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-error is the lowest shared failure layer. It owns AkitaError and reusable exact usize formulas in akita_error::checked. These formulas return Option; each caller maps failure to the AkitaError variant that describes its protocol boundary. Field arithmetic lives in the shared external jolt-field crate.
  • akita-planner owns offline schedule search and artifact emission. Normal search is Cfg-free and is not on the verifier runtime dependency path. The optional catalog-gen feature enables akita-config, so artifact-emission binaries may name concrete CommitmentConfig presets.
  • akita-verifier depends on akita-config, akita-schedules, and akita-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 umbrella akita-pcs package.

End-to-end lifecycle

  1. Preset and trusted catalog selection. The caller picks a CommitmentConfig preset and loads the matching schedule artifact from the same trusted parameter source used for setup or preprocessing. The caller constructs one AkitaCommitmentScheme<Cfg> with that catalog. The catalog contains complete expanded rows. Planner search remains offline. Each row selects SubringCoefficientPacking or EvaluationTrace for every nonterminal fold. EOR is present only for an evaluation trace opening over a proper extension field. See Fold path and field geometry.
  2. Setup. akita-setup scans the rows in the scheme's trusted catalog and expands the setup (Ajtai matrices and stride envelopes) to cover the requested capacity.
  3. Commit. The application consumes its polynomials into a reusable CpuBackend and commits the imported source using GroupContext. 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.
  4. Claims. The caller supplies ordered PolynomialGroupClaims; each group owns its complete point, evaluations, and commitment.
  5. Prove. batched_prove receives 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.
  6. Verify. batched_verify resolves 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 share bind_transcript_instance_descriptor so 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 D and 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

TypeRole
AkitaError, akita_error::checkedShared 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_dimsA/B/D commitment-matrix ring dimensions and schedule validation
CommitmentConfigSingle 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>
CommittedGroupParamsOne fold's ordered groups, shared D matrix, payload mode, source encoding, and witness chunk layout
FoldParams, TerminalFoldParams, FoldScheduleVerifier-visible nonterminal, terminal, and complete schedule structure
PlannerPolicyCfg-free projection of a preset for akita_planner::find_schedule; derive via akita_config::policy_of::<Cfg>(chunking)
DensePoly, OneHotPoly, CommitmentSource, CommitmentExecutorD-free polynomial storage, commitment representations, and the checked split-or-fused commitment boundary
ProverBackend, focused opaque kernel traitsPublic protocol operations with backend-owned opening, EOR, fold, and sumcheck state
WitnessLayout, WitnessUnitLayoutCanonical digit-innermost group-and-chunk ranges (opening layout)
Vec<u8> returned by batched_proveCanonical Spongefish argument stream, consumed in protocol order by batched_verify with EOF and grinding-plan completion
PolynomialGroupClaimsOne commitment group's complete opening point, evaluations, and commitment
OpeningClaimsOrdered group-owned public claims in transcript order
OpeningClaimsLayoutValue-free group arities and polynomial counts for setup and schedule lookup
GroupCommitPhaseParams, CommittedGroupSource-free public commitment geometry and its commitment rows
SourceHandle, CommitmentHandleBackend-owned immutable source and reusable source-retaining commitment
ProverOpeningData, SelectedProverOpeningDataOrdered opaque commitment handles bound to public claims and one exact schedule selection
OpeningScheduleSelection, GroupBatchStatementExact generated-row identity and verifier-side self-describing opening statement
ValidatedScheduleCatalogConfig-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 statesFiat--Shamir state, proof emission/receipt, domain separation, challenges, and EOF checking
AkitaInstanceDescriptorCanonical 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.md for 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.rs defines CommittedGroupParams.
  • crates/akita-params/src/schedule/profiles.rs defines GroupCommitPhaseParams.
  • crates/akita-params/src/layout/params/precommitted.rs defines GroupOpenPhaseParams and GroupOpeningPlan.
  • crates/akita-params/src/schedule.rs defines FoldParams, TerminalFoldParams, and FoldSchedule.
  • crates/akita-schedules/src/resolve.rs validates 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.md for the current planner overview, search model, and artifact generation.
  • crates/akita-planner/src/ owns search and emission. Runtime catalog expansion and audit live in crates/akita-schedules/src/.
  • crates/akita-params/src/proof_size.rs and crates/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/, and crates/akita-schedules/src/artifact.rs.
  • book/src/usage/profiling.md and .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, where K is 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:

LabelValue
domainakita/commitment/public-field-stream
derivationshake256-paged-v1
page_field_elements4096 as little-endian u64
seedthe 32-byte public seed
fieldthe 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 profileFirst mapSecond map
q128168
q643216
q326432

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.rs
  • crates/akita-cpu-backend/src/commitment/api.rs
  • crates/akita-types/src/setup_contribution/plan/physical_b.rs

Public-stream and view sources:

  • crates/akita-types/src/proof/setup.rs
  • crates/akita-params/src/layout/flat_matrix.rs
  • crates/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.rs constructs setup and validates cached public matrices against their seed. Its tests cover seed and cache mismatches.
  • crates/akita-cpu-backend/src/commitment/api.rs checks standalone commitment profiles, computes inner images, and executes sliced outer commitments.
  • crates/akita-cpu-backend/src/commitment/portable.rs defines the retained prover state and tests its canonical serialization and shape checks.
  • crates/akita-cpu-backend/src/opaque/recursive/commit.rs commits 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.rs binds the group context and owns the single transcript squeeze.
  • crates/akita-challenges/src/sampler/xof.rs defines the indexed SHAKE256 stream and unbiased bounded draws.
  • crates/akita-challenges/src/sampler/position_sample.rs implements the partial Fisher--Yates paths.
  • crates/akita-challenges/src/sampler/signed_sparse.rs assigns magnitudes and signs.
  • crates/akita-challenges/src/sampler/op_norm.rs checks 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:

SectionWhat it fixes
AlgebraBase modulus and field extension degrees
SetupDecomposition, SIS modulus profile, compression policy, setup seed digest, protocol feature flags
PlanSchedule selection and the effective schedule digest
GrindingThe ordered grinding plan and its wire contract
CallCommitment-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:

  1. Prepare the opening claim. If evaluation trace over a proper extension requires extension-opening reduction, replay that reduction first.
  2. Absorb the complete opening payload, either compressed or raw , then draw the application claim-batching coefficients.
  3. Consume the fold-response nonce and draw the sparse fold challenges for each group.
  4. Absorb the next-witness binding. It is a recursive commitment payload or, on the last edge, the terminal inner-image state.
  5. Draw the ring-switch challenge , followed by the range and row points .
  6. 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.
  7. 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.

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.rs constructs and binds the shared descriptor and grinding plan.
  • crates/akita-types/src/instance_descriptor/mod.rs owns descriptor fields, canonical serialization, and version validation.
  • crates/akita-transcript/src/proof_stream.rs owns state construction, context framing, canonical atom codecs, bounded bytes, and EOF-compatible proof transport.
  • crates/akita-params/src/transcript_grinding/plan.rs defines the ordered plan; crates/akita-types/src/transcript_grinding/replay.rs couples nonce transport, predicate checks, challenges, and plan progress.
  • crates/akita-challenges/src/sampler/xof.rs derives the indexed sparse challenge streams.
  • crates/akita-verifier/src/fold/mod.rs and crates/akita-verifier/src/fold/terminal.rs enforce fold and terminal replay order.
  • crates/akita-pcs/tests/transcript_hardening.rs tests ordering and prover/verifier agreement; crates/akita-pcs/tests/fold_linf.rs covers 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.

InputWhat it means
Public opening claimsOrdered commitments, opening points, and claimed polynomial values
Private source dataPolynomial or recursive witness values plus the hints created when they were committed
Public setupThe A, B, and D matrix entries required by this scheduled level
Scheduled parametersRing 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:

  1. the folded response agrees with the source blocks and fold challenges;
  2. the inner A matrix agrees with the source digits;
  3. the outer B matrix agrees with the public commitment; and
  4. 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.

StageWhat it provesWhat it leaves behind
Stage 1Every new witness entry is in the scheduled balanced digit range; an L2 route also proves the physical response normOne range-image evaluation used by Stage 2
Stage 2The ring-switched physical relation, Stage 1 output, and incoming opening claim all agree with the committed successor witnessThe successor witness opening claim
Stage 3The claimed A, B, and D setup contribution is the correct product sum for a prepared setup prefixA 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

LevelSourceMain responsibilityOutput
RootApplication polynomial groupsBatch the requested openings and enter the recursive fold pathFirst recursive witness claim, plus an optional setup claim
Recursive nonterminalWitness and optional setup group from the predecessorAuthenticate the handoff and reduce it to the next opening claimNext witness claim, plus an optional setup claim
TerminalFinal clear witness bound by its predecessorCheck consistency, A relation, evaluation trace, encoding, and scheduled norm directlyAccept 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

  1. Field-to-ring evaluation reduction
  2. Semantic relations in an Akita fold
  3. Raw and compressed realizations
  4. Checking ring relations over a field
  5. Opening points and digit-innermost layout
  6. Fold path and field geometry
  7. 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

ResponsibilityProverVerifier
Top-level schedule walkakita-prover/src/protocol/prove/root.rsakita-verifier/src/fold/verify.rs
Root and recursive fold orchestrationakita-prover/src/protocol/prove/fold/akita-verifier/src/fold/
Extension-opening reductionakita-cpu-backend/src/opaque/recursive/opening/akita-verifier/src/stages/opening_claims/extension_claim.rs
Stage 1 range and norm proofakita-cpu-backend/src/opaque/sumcheck/digit_range/ and physical_l2_norm.rsakita-verifier/src/stages/stage1.rs
Stage 2 fused relationakita-cpu-backend/src/opaque/sumcheck/relation_range_image/akita-verifier/src/stages/stage2.rs
Stage 3 setup productakita-cpu-backend/src/opaque/sumcheck/stage3/akita-verifier/src/stages/stage3.rs
Terminal pathakita-prover/src/protocol/prove/suffix.rsakita-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:

  1. The generated schedule and proof shape still describe every message.
  2. Prover and verifier absorb public data and proof messages in the same order.
  3. Source, witness, relation, and challenge indexes use the same physical layout.
  4. Every relation row is interpreted in its scheduled native ring before lifting or batching.
  5. Stage 1 output and the incoming opening claim are both bound inside Stage 2.
  6. Stage 3 is present exactly on offloaded setup edges.
  7. The successor receives the exact witness and setup claims produced by its predecessor.
  8. 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 methodPartial carried into the foldScalar target bound here
EvaluationTracefull-ring the trace target; it equals in the base-field case
SubringCoefficientPackingshorter 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:

RingDerived fromMeaning
, , 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 rowafter 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:

  1. Prepare the opening weights. prepare_opening_point constructs , , and .
  2. Evaluate the ring polynomial. evaluate_claims_at_prepared_point returns the position-folded rings and the temporary ring .
  3. Recover the scalar evaluation. scalar_opening_from_folded_ring computes .
  4. Prepare the trace factors. prepare_evaluation_trace_group_parameters prepares the block point underlying , the gadget weights , and the inner trace weights .
  5. Construct the trace weights. build_evaluation_trace_weights combines those factors with the claim coefficients and physical locations to construct .
  6. Fuse the Stage-2 relation. accumulate_fused_relation_linear_signed adds 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 valueMathematical 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::evaltemporary
PreparedEvaluationTraceClaim::claimed_evaluation
PreparedEvaluationTraceClaim::claim_coefficientsclaim-batching coefficients
RingRelationGroupWitness::folded_opening, in its EvaluationTrace variantposition-folded rings
RingRelationGroupWitness::e_hatdigit rings
PreparedFold::evaluation_trace_claim carried into Stage 2
PreparedFold::relation_groups, through PreparedRelationGroupPublic::kind()prepared , , and for each evaluation-trace group
PreparedFold::witness_handleopaque 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_pointblock 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:

  1. Prepare the point. PreparedSubringCoefficientPackingPoint checks and prepares the packing, tail, position, and block weights.
  2. 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.
  3. Fold and verify. fold_coefficient_packing_group folds 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:

  • EvaluationTrace keeps a full ring partial and proves the relation in .
  • SubringCoefficientPacking keeps 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:

  1. the opening data computed from the old polynomial;
  2. the inner and outer commitments; and
  3. 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:

SegmentWhat it digit-decomposesWhy 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

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 rowsCountMeaningRight-hand side
consistencyEquation (12a)
rowsEquation (13)
rowsEquation (14)
rowsEquation (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.

ViewRaw realizationCompressed realization
Public payload
Compression-digit witnessnone
right-hand sideszero
Additional compression rowsnone
What binds the payloadthe ordinary commitment equations directlythe 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:

  1. Compute the semantic commitment
  2. Decompose and repack into so that
  3. Apply the first rank-one map:
  4. Decompose and repack into so that
  5. 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:

ProfileFirst ring First imageTerminal ring Terminal payload
q128256 bytes128 bytes
q64256 bytes128 bytes
q32256 bytes128 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 rowsCountRight-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:

StatementFormPhysical ring row?Ring-switch quotient?
opening commitmentyesonly in QuotientLift
evaluation correctnessnono

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

  1. Create and retain the commitment-side material. The standalone/root commitment paths in commitment API compute the semantic outer commitment and compress it. The recursive commit_witness computes the same semantic value, then follows the payload mode selected for that level. A raw recursive level exposes directly. A compressed commitment passes it to execute_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.
  2. Build the fold-side objects. RingRelationProver::prepare coordinates 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_witness combines the retained material with a newly computed chain for , producing the terminal payload and storing both chains as CompressionWitnessMaterialization.
  3. Assemble the mode-selected public statement. Raw mode calls assemble_relation_rhs with and . Compressed mode instead calls assemble_compressed_relation_rhs with and . The latter emits zero ordinary and first-map right-hand sides, followed by the terminal payloads on the rows.
  4. Construct the committed relation witness. cpu_recursive_witness_build derives from the semantic inner rows stored in the hint, and emits , , and . In quotient-lift mode it invokes compute_multi_group_relation_quotient to 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. WitnessLayout determines which ranges and alignment are live.
  5. Prepare the Stage 2 relation evaluators. Quotient lifting uses the factored build_relation_lane_weights path for the consistency, , , 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 in opaque/relation_weights/compiler.rs. Compressed mode additionally uses build_compression_relation_weights or its reduced counterpart for the recomposition, , and mode-selected compression-quotient contributions, while NegativeBinarySupport restricts 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 accessorMathematical 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 modezero 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:

FieldMathematical meaning
foldaccepted CPU fold handle retaining the centered response coefficients and its challenges
folded_openingmethod-selected opening state: the rings for evaluation trace, or the packed fold product for coefficient packing
e_hatopening digits
inner_relationretained semantic inner rows used to reconstruct
role_dimsnative 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:

MethodMain ideaEffect on the witness
Quotient liftingRecord the reduction in a private quotient polynomialAdd its digits to the next witness
Quotient-free checking, called ReducedEvaluation in codeInclude the reduction in public weights on the existing coefficientsAdd 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

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.

PayloadQuotient liftingReduced 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.rs defines both modes and the allowed transition. FoldSchedule::validate_structure enforces the complete schedule restrictions.
  • witness_build/finalize.rs constructs the mode-selected witness inside the CPU backend. Reduced evaluation branches before quotient construction. WitnessLayout owns the actual ranges.
  • ring_switch.rs samples after the caller binds the outgoing witness. The CPU backend's relation_weights/stage2.rs then selects factored or dense relation weights for Stage 2.
  • ring/residue.rs implements the recurrence. Its tests compare the result with explicit signed multiplication and ring products, including points where .
  • relation/evaluation.rs selects 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.

ObjectEffect of multi-chunking
Replaced by full-width local responses
Partitioned by block range; total width is unchanged
Remain aggregate commitment images
Semantic rows and targetsRemain 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 familyNative 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 methodProduction useEOR
SubringCoefficientPackingRequired at levels 0 and 1 and every multi-chunk fold; optional at later single-chunk foldsomitted
EvaluationTraceEligible single-chunk folds at level 2 or later and the terminal pathrequired 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:

  1. prove_root prepares coefficient packing for every root group.
  2. Recursive folds use packing at level 1 and every multi-chunk fold; later single-chunk folds may dispatch to packing or evaluation trace.
  3. Shared prove_fold runs the ring relation, ring switch, and sumchecks.
  4. 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/ and crates/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:

  1. the direct packed scalar row recombines the packed opening digits into the original scalar claim; and
  2. 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

RingDefinitionPhysical role
A ringsource witness and A rows
challenge subringsparse fold challenges
extension opening ringpacked 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:

ObjectLogical shapeBase-field storageWidth
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

  1. The schedule fixes , , the canonical extension basis, and the sparse challenge family.
  2. The prover forms each packed partial and digit-decomposes its base-field coordinates.
  3. The prover binds the complete D payload, or its compressed H payload.
  4. The transcript samples one for each live claim/block pair.
  5. The prover folds the A-ring sources with and computes .
  6. The prover binds and the next witness; only then does the transcript sample .
  7. 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.rs assembles ordinary relation terms.
  • crates/akita-cpu-backend/src/opaque/witness_build/relation_quotient.rs computes the role-native ordinary quotients and sparse high-half contributions.
  • crates/akita-cpu-backend/src/arithmetic/ring_switch.rs selects the retained or streamed CPU kernels.
  • crates/akita-prover/src/protocol/ring_switch.rs assembles the ring-switch witness and proof state.
  • crates/akita-cpu-backend/src/opaque/witness_build/coefficient_packing.rs forms packed partials and the packing quotient.
  • crates/akita-cpu-backend/src/arithmetic/coefficient_packing_fold.rs holds the packing map, the direct partial and scalar-opening formulas, and the subring-challenge fold products.
  • crates/akita-params/src/layout/subring_packing_geometry.rs defines and validates the packing geometry.
  • crates/akita-types/src/proof/coefficient_packing_relation.rs validates 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:

  1. 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 L2 route also proves the complete physical response norm in the final Stage 1 substage.
  2. 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.
  3. 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

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:

BasisProduct substagesFinal leaf
4noneone quadratic leaf
8noneone quartic leaf
16arity 2, emitting 2 child claimsbatch of 2 quartic leaves
32arity 4, emitting 4 child claimsbatch of 4 quartic leaves
64arity 2, emitting 2 claims; then arity 4, emitting 8 claimsbatch 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:

  1. absorbs the child evaluations in canonical order;
  2. samples a fresh interstage challenge ;
  3. assigns weights in that same order;
  4. batches the child evaluations into the next carried claim; and
  5. 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 :

  1. satisfies the ring-switched fold relation;
  2. Stage 1's virtual range-image value is correctly derived from ; and
  3. 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:

ObjectShapeWhat it removes or binds
one field elementevaluates the ring-polynomial variable
a point over matrix rowsbatches all relation rows into one virtual row
one field elementbatches range-image consistency with the linear claims
one field element in compressed modebatches the zero-valued constraint
Stage-1 output point over flat witness addressesidentifies the carried range-image evaluation
Stage-2 output point over flat witness addressesreduces 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 group g; 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.rs contains 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.rs builds the prover's tensor partials and factor tables.
  • crates/akita-types/src/extension_opening_reduction.rs holds 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:

  1. Distributable witness. The witness can be split across independent machines so that each machine owns and processes only its share.
  2. 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.
  3. 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:

  1. 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.
  2. 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 valueCompressed representationRaw representation
Current commitment, the end of the B-image compression chainB image
Opening payload, the end of the D-image compression chainD image
Recursive successor bindingSuccessor'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.rs checks recursive candidate contraction and derives terminal candidates.
  • crates/akita-planner/src/schedule_params/suffix_dp.rs records the successor-aligned physical lengths and checks offloaded-edge contraction.
  • crates/akita-cpu-backend/src/opaque/recursive/commit.rs prepares the successor's physical witness, commitment, or terminal inner state.
  • crates/akita-types/src/proof/levels.rs defines the level records and successor-binding variants.
  • crates/akita-verifier/src/fold/mod.rs binds the successor before replaying ring switching and the sumcheck stages.
  • crates/akita-verifier/src/fold/suffix.rs carries the resulting point and value into the next fold, and crates/akita-verifier/src/fold/terminal.rs validates terminal-state identity.
  • crates/akita-pcs/tests/transcript_hardening.rs checks 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.

ModeWhat happens during verificationExtra proof work
DirectThe verifier scans the active public setup prefix and computes the weighted sum.None. The value is checked inside Stage 2.
OffloadedThe 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_len is the number of setup coefficients that can receive nonzero weight in the fold;
  • n_prefix is 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:

  1. Stage 2 produces an opening claim for the next folded witness.
  2. 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, and OneHotMultiChunkW8R3).

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 configurationRecursive artifactVariable counts
fp32::Densefp32_dense_recursive.aks20, 22, 24, 26, 28, 30
fp64::Densefp64_dense_recursive.aks21, 23, 25, 27, 29
fp128::Densefp128_dense_recursive.aks20, 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

ResponsibilityPrimary implementation
Enable the recursive catalogcrates/akita-config/src/recursive_commitment.rs
Search direct and offloaded suffixescrates/akita-planner/src/schedule_params/suffix_dp/
Build recursive candidates and prefix requirementscrates/akita-planner/src/schedule_params/candidate/recursive.rs and candidate/setup_prefix.rs
Define prefix identities and proof datacrates/akita-params/src/layout/setup_prefix_slots.rs and crates/akita-types/src/proof/setup_prefix.rs
Build the shared setup contribution plancrates/akita-types/src/setup_contribution/
Evaluate the setup contribution at the Stage 2 pointcrates/akita-verifier/src/setup_contribution/
Materialize required prefix commitmentscrates/akita-setup/src/recursive_prefixes.rs
Prove the setup productcrates/akita-cpu-backend/src/opaque/sumcheck/stage3/
Verify Stage 3crates/akita-verifier/src/stages/stage3.rs
Enforce the recursive fold handoffcrates/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:

  1. Matrix evaluation at a point defines the physical rows and columns.
  2. The Stage 2 fused check shows how the relation, range image, and schedule-selected opening method share one final witness evaluation.
  3. Evaluation trace explains the trace-based opening method. Root fold and ring switch explains subring coefficient packing.
  4. 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.
  5. The distributed relation verifier explains exact dyadic ownership and unequal chunks.
  6. 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:

  1. Bind the instance and absorb the opening batch shape into the transcript.
  2. Resolve the exact trusted row named by OpeningScheduleSelection. Artifact identity and row digests are checked before the ordered GroupCommitPhaseParams values are compared with the resolved row. The verifier never runs planner search.
  3. Replay the structural folds in fold/: the root fold followed by every recursive fold, using the schedule-selected CommittedGroupParams.
  4. Check the terminal witness directly against its predecessor-bound t state. The terminal relation is consistency | A; it has no outer u, 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:

  1. check the opening and commitment payload shapes, then read the fold response and draw the fold challenges;
  2. assemble the ring-relation instance and receive the successor witness;
  3. replay the ring switch (stages/ring_switch.rs) and derive the relation claim and range-image plan (stages/relation_claim.rs);
  4. replay Stage 1 (stages/stage1.rs), then prepare the Stage 2 opening semantics (stages/opening_semantics.rs);
  5. replay the Stage 2 rounds (stages/stage2.rs), then Stage 3 when the successor defers the setup contribution (stages/stage3.rs);
  6. 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:

  1. validates the trusted artifact family, protocol epoch, active policy, and runtime challenge hooks when the catalog is installed;
  2. resolves the fixed-width row digest by bounded lookup;
  3. checks every ordered public committed profile against the resolved row;
  4. re-audits every A, B, D, recursive, and terminal SIS matrix against the canonical security table, role, modulus, rank, width, bound, and ring dimension;
  5. checks root, recursive, setup-prefix, challenge, witness-partition, terminal response, and full terminal norm cap geometry;
  6. checks that the schedule fits the setup field capacity; and only then
  7. 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-used jolt-field code
  • akita-config (every CommitmentConfig method reachable from batched_verify)
  • akita-schedules artifact identity, row resolution, and canonical resolved-row audit paths

Rules for contributors

  1. 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.
  2. Use akita_error::checked for reusable exact usize formulas. The functions return Option, so the caller maps failure to the AkitaError variant that matches the protocol boundary. A direct standard library checked_* call remains appropriate for one local operation.
  3. Do not use wrapping or saturating arithmetic for exact sizes and indices. Reject arithmetic that cannot represent the required geometry.
  4. Strengthen validation at deserialization, setup construction, schedule selection, CommittedGroupParams construction, and verifier API entry points rather than sprinkling checks through hot loops.
  5. 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:

FamilyPurposeMain witness segment
consistencyTie the folded response to the opening digitsz_hat, e_hat
A or innerCheck the inner commitment imagez_hat, t_hat
B or outerCheck the outer commitment imaget_hat
D or openingCheck the opening commitment imagee_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:

  • Z is replicated once per chunk. An empty chunk keeps its Z range, and the honest prover writes zero there.
  • E is partitioned by exact block ownership. It contains the opening digits for claims and blocks owned by that unit.
  • T is 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 tau1 equality 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 WitnessLayout and 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.rs and crates/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:

  1. The witness agrees with the Stage 1 range result.
  2. The witness satisfies the relation matrix.
  3. 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:

  • EqPolynomial evaluates the range image equality factor.
  • RelationMatrixEvaluator evaluates the ordinary relation matrix.
  • CompressionRelationWeights and NegativeBinarySupport evaluate the F and H compression relations and their digit constraints.
  • PreparedEvaluationTrace evaluates an evaluation trace opening.
  • CoefficientPackingCompactFactors evaluates 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 in crates/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 E address.

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 E addresses: 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_y selects the coefficient inside a setup ring;
  • rho_setup_idx selects 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, and SetupIndexWeightMle;
  • crates/akita-verifier/src/relation/evaluation.rs for direct or deferred selection; and
  • crates/akita-verifier/src/stages/stage3.rs for 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:

piecesizeaxis order (outermost → innermost)kind
e_hat^(j)do · C · B_jdig → claim → block_localpartitioned
t_hat^(j)do · n_A · C · B_ja_row → dig → claim → block_localpartitioned
z_hat^(j)dc · df · num_positions_per_blockdc → df → blkreplicated
r_tailrows · levelslevel → 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 at block_local ∈ [0, B_j), but it names the global block blk_g = s_j + block_local, which is what the folding challenge c_α 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.

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.

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 .

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

caseoverhead
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 — on e_hat^(j), for . Partitioned: and , so the pieces collectively are exactly the single-machine , only re-laid-out by machine.
  • B · t_hat — on t_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_hat and B · t_hat, the partition only re-routes which e/t column 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 distributed e_hat address: the machine is the unique mac whose exact range satisfies , and block_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 machine mac's piece. The total column count is unchanged.
  • T_col[g][c] (B · t_hat). The same with the extra a_row axis and per-group sparsity, against the distributed t_hat layout; reuses eq_high_t.
  • Z_comb[c] (A · G_fold · z_hat). For each A column , sum over machines: . Each is the G_fold weighted equality sum over the df axis of machine 's z_hat segment. Build cost is ; in the non-power-of-two num_positions_per_block case 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

stepcostdone once per
eq_high_e, eq_high_t, eq_high_z tablesverifier
W_col, T_col buildsverifier
Z_comb buildverifier
-evaluations ring opsper row
per-row inner productper row
dominant -evaluations — UNCHANGEDtotal

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):

componentsingle-machinedistributed (verifier total over all )delta
e_hat consistencyheavy term unchanged; light
t_hat consistencyheavy term unchanged; light
z_hat tensor (replicated)cheap term (no tiling)
D·e_hat, B·t_hat setup scan-evals over full , identicalnone
A·G_fold·z_hat setup scan (dominant) -evals -evalsnone
combined column-weight build— field opsadditive, cheap
r_tail rowsone quotientone summed quotientnone

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.rs owns physical chunk, group, and segment addresses.
  • crates/akita-params/src/witness/chunk_partition.rs owns 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.rs combines structured, setup, quotient, and compression contributions.
  • crates/akita-verifier/src/relation/evaluation_trace.rs evaluates 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:

  1. Check that the scheduled terminal geometry matches the remaining witness and that there is no deferred setup-prefix opening.
  2. Absorb the incoming inner-image binding and check that the response's coefficients match it exactly.
  3. Prepare the incoming point and claim. Replay extension-opening reduction when required.
  4. Absorb the , consume the terminal fold-response nonce, and derive the sparse . The L2 route also uses its scheduled challenge admission rule.
  5. Absorb the remaining response bytes, decode , and check its bounds.
  6. 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.rs checks the predecessor binding and replays the terminal transcript.
  • crates/akita-verifier/src/terminal/direct.rs checks the decoded response norm, ring relations, and opening trace.
  • crates/akita-verifier/src/terminal/ntt.rs evaluates the exact A product.
  • crates/akita-params/src/golomb_rice.rs implements the codec and its canonical-decoding tests.
  • crates/akita-params/src/layout/tail_segments.rs defines the response layout and transcript segments, and crates/akita-types/src/proof/tail_segments.rs defines the wire response.
  • crates/akita-types/src/field_reduction.rs implements subfield recovery. crates/akita-pcs/tests/transcript_hardening.rs supplies 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/, and norm_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.rs owns the two physical collision formulas. crates/akita-types/src/proof/relation_range_image.rs owns the physical response map. crates/akita-cpu-backend/src/opaque/sumcheck/physical_l2_norm.rs and crates/akita-verifier/src/stages/physical_l2_norm.rs own proof and replay.
  • specs/archive/2026-Q3/weak-binding-norm-fix.md records 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) and crates/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:

  1. The source owns only its logical witness.
  2. Derived data belongs to the operation that uses it.
  3. 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.rs fuses the physical norm with the final range leaf.
  • crates/akita-params/src/sis/physical_l2.rs defines 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.

  1. Read Multilinear extensions and sum-check to see how a table becomes a polynomial and how a large identity is reduced to one evaluation.
  2. Read Cyclotomic rings and extension fields to learn where Akita stores coefficients and why some evaluation points live in a larger field.
  3. 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.
  4. Read Lattices and Module-SIS for the hard problem behind the commitment.
  5. Read Polynomial commitments and binding to connect setup, commitment, opening, verification, and the security assumption.
  6. 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.

ChapterThe question it answersCurrent depth
Cyclotomic rings and extension fieldsWhat 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 arithmeticHow does Akita multiply and transform ring elements efficiently across its supported prime sizes?Current implementation narrative, including scalar, AVX2, and AVX 512 paths.
Gadget decompositionHow 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 arithmeticHow are protocol field values represented, reduced, accumulated, and sampled?Production field families, canonical arithmetic, exact sampling, extension operations, and accumulator bounds.
Lattices and Module-SISWhat 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-checkHow 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-checkHow 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 reductionHow 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 bindingWhat 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 notationWhat do recurring Akita names and symbols mean?Current lookup reference for protocol terms, catalog rows, and notation.
Spec indexWhich design records are live, implemented, or retained as history?Current maintainer index.
ReferencesWhere 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:

  1. the mathematical statement;
  2. the public parameters that instantiate it;
  3. the code that validates those parameters;
  4. the verifier code that relies on the statement;
  5. 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:

ConceptPrimary code owner
Prime fields, extension fields, packed values, and field kernelsexternal jolt-field
Cyclotomic rings, NTTs, modules, and gadget decompositionakita-algebra
Generic sumcheck proof types and driversakita-sumcheck
Transcript construction and challenge samplingakita-transcript and akita-challenges
SIS parameters, commitments, proof shapes, and schedulesakita-types
Concrete configuration policyakita-config
Commitment and proof executionakita-prover
Verifier replay and rejectionakita-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:

FamilyBase field sizeEvaluation field
fp32About 32 bitsDegree 4 extension of the base field
fp64About 64 bitsDegree 2 extension of the base field
fp128About 128 bitsThe 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

QuestionPrimary 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.

FamilyBase-field modulusChallenge 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.

ProductAccumulatorProven term headroom
fp32 by fp322 u128 slots2^64
fp64 by fp642 u128 slots2^64
fp128 by fp1284 u128 slots2^64 - 1
fp128 by u643 u128 slots2^64 - 1
fp32 degree-4 extension product4 u128 slots2^61
fp64 degree-2 extension product4 u128 slotsmore 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.

PropertyPrimary source
Registered pseudo-Mersenne types and exact rejection samplingsolinas/mod.rs
32- and 64-bit word arithmeticsolinas/word.rs
128-bit two-limb arithmetic and fused multiply-addsolinas/fp128.rs
Unreduced products and accumulatorssolinas/unreduced.rs
Extension arithmeticsolinas/ext.rs
Production field selectioncrates/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 tierCRT primesBase representation
Q3222 i32 residues
Q6433 i32 residues
Q12866 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, and avx512ifma;
  • AKITA_SCALAR_NTT is not set to 1;
  • the ring degree is D64 through D2048; 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:

PrimeValueDistance below (2^{50})
(p_0)112589990682624116383
(p_1)1125899906629633212991
(p_2)11258999057448971097727

The exact cache uses the smallest CRT representation that meets the strict CRT bound:

Field tierIFMA residuesIFMA selection rule
Q321 u64 residueUse 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.
Q642 u64 residuesUse the IFMA form only when the two base residues fit. Otherwise use the ordinary Q64 profile, which can add 12289.
Q1283 u64 residuesUse 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:

ProfileBase residue bytes per coefficientLimb residue bytes per coefficient
i32, q12826 with the 12289 tail40 at (L = 5)
IFMA, q12828 with the 30 bit tail32 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.md records the implemented exact signed digit and terminal NTT contract.
  • book/src/usage/profiling.md documents the NTT matvec benchmarks and their cache labels.
  • docs/crt-ntt-capacity-profile.md records 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 toContinue with
Learn the idea without prior knowledge of proof systemsThe chapter in order, starting with the base 4 example
Supply values to AkitaWhere Akita uses decomposition and source width and source shape
Change or review the implementationHow digits are stored, the code path, and the review checklist
Audit how the protocol rule reaches the shipped codeFrom the protocol rule to the code
Study performanceFrom 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.

SymbolMeaning
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.

ValueWhy it is decomposedBound used for its depth
Root committed sourceIt is the application data entering the first commitmentlog_commit_bound
Recursive committed sourceIt is the recursive digit witness produced by an earlier foldThe source bound stored by the schedule
Opening valueIt is used to prove a claimed polynomial evaluationlog_open_bound or the full field width
Setup prefixIt contains public setup field elements used by a later foldThe full field width
Folded responseIt is the response produced during one foldThe 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:

  1. The interval declared by log_commit_bound.
  2. 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 intervalRust storage
1 to 8i8
9 to 16i16

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:

  1. DecompositionParams in crates/akita-params/src/config.rs records log_basis, log_commit_bound, and the optional log_open_bound.
  2. crates/akita-params/src/sis/decomposition_digits.rs computes the exact digit count for each protocol role.
  3. The generated schedule stores the selected counts in CommittedGroupParams.
  4. crates/akita-algebra/src/ring/cyclotomic/decomposition.rs performs the coefficient decomposition and rebuilding operation.
  5. crates/akita-cpu-backend/src/kernels/linear/decompose.rs uses the packed i8 kernel. Wider inner decompositions use crates/akita-cpu-backend/src/arithmetic/exact_i16.rs.
  6. crates/akita-params/src/sis/committed_source.rs checks the accepted source range and source class.

Supporting limits live in these files:

  • crates/akita-params/src/signed_digit.rs selects i8 or i16 storage.
  • crates/akita-algebra/src/ring/crt_ntt_repr/lut.rs prepares signed i8 digits for the CRT and NTT commitment path.
  • crates/akita-schedules/src/runtime.rs validates schedule basis ranges.
  • crates/akita-config/src/proof_optimized.rs defines 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 traceExplanation in this chapterCurrent implementation
A coefficient is rebuilt from balanced powers of the baseThe general decomposition rule and the gadget matrixdecomposition.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 digitThe exact range and full field elementsdecompose_centering_threshold applies the exact threshold, including the 128 bit overflow boundary
Every committed digit is in the balanced setThe balanced digit setlayout/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 depthsWhere Akita uses decompositiondecomposition_digits.rs separates root sources, recursive sources, setup prefixes, openings, and folded responses
Prover and verifier use the same choiceThe public scheduleThe resolved schedule stores each role specific basis and depth in CommittedGroupParams
A committed source satisfies the assumptions used to size itSource width and source shapecommitted_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 digitsHow digits are storedsigned_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 extractionThe fast path and fallbackdecomposition/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.

  1. Check that extraction produces digits in and that their weighted sum rebuilds the original coefficient modulo .
  2. 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.
  3. Check that the depth selector covers the correct range for each role. Full field values and smaller signed sources use different centering rules.
  4. Check that source admission applies both parts of the contract. The numeric interval and the declared source class are independent.
  5. Check that the resolved schedule, proof layout, prover, and verifier all use the same role specific depth and basis.
  6. Check that the flat, ring, i8, i16, scalar, NEON, and AVX2 paths agree on digit order and centering at their boundaries.
  7. 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

QuestionPrimary 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:

002
105
017
1111

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

RuleImplementation
Evaluate a multilinear tableakita-algebra/src/poly.rs
Build equality-polynomial tablesakita-algebra/src/eq_poly.rs
Represent and compress round polynomialsjolt-poly/src/univariate.rs and jolt-poly/src/compressed_univariate.rs
Define prover and verifier instance contractsakita-sumcheck/src/traits.rs
Encode proofs and verify ordinary roundsakita-sumcheck/src/types.rs
Batch claims and right-align shorter instancesakita-sumcheck/src/batched_sumcheck.rs

For a review, check these facts together:

  1. Table indexing and challenge order agree.
  2. Every round polynomial respects the declared degree bound.
  3. The transcript absorbs the claim and round message before sampling the challenge that depends on it.
  4. Proof decoding derives the round count and message width from trusted configuration.
  5. The final output claim is compared with the expected oracle evaluation.
  6. 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

RuleImplementation
Equality polynomial definition and tablesakita-algebra/src/eq_poly.rs
Split equality state and suffix cachesakita-algebra/src/split_eq.rs
Factored prover interfaceakita-sumcheck/src/traits.rs
Factored round message and proof encodingakita-sumcheck/src/types.rs
Direct prover/verifier functions and normalized claim updateakita-sumcheck/src/single.rs

For a review, check these facts together:

  1. The challenge order used by , the data table, and GruenSplitEq agrees.
  2. The declared degree bounds apply to the inner polynomial , not the product .
  3. The proof shape fixes the number of rounds and stored coefficients before decoding.
  4. Prover and verifier use the same and challenge in every update.
  5. The final comparison uses the normalized oracle value, without an accumulated equality scale.
  6. 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.

ObjectMeaningHow the verifier obtains it
and the commitmentIncoming opening claimAlready available at the EOR boundary
Original and packed witness tablesThe prover does not send these full tables in EOR
Claimed column partialsSent by the prover
Coordinates and repacked rowsDerived from the received
Public coordinate tablesDerived from and the fixed basis
Row and sumcheck challengesDerived from the transcript in order
Batched public factor and its final evaluationDerived from
Sumcheck input targetDerived from the rows and
Degree-two round polynomialsSent in compressed form
Claimed final productSent 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_point evaluates 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, and final_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.rs performs bounded honest response search.
  • crates/akita-challenges/src/sampler/xof.rs gives 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.rs checks the final response norm and direct relations.
  • crates/akita-pcs/tests/fold_linf.rs and crates/akita-pcs/tests/transcript_hardening.rs provide 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

TermMeaning
Polynomial commitment scheme (PCS)A protocol that commits to a polynomial and later proves a claimed evaluation without sending the whole polynomial.
Multilinear polynomialA polynomial that has degree at most one in each variable. Its values on the Boolean cube determine it everywhere.
Evaluation tableThe values of a multilinear polynomial at all Boolean inputs. A polynomial in variables has a table of length .
CommitmentA short public value that binds the polynomial for later opening checks. This does not promise hiding; see Akita's current privacy boundary.
OpeningA proof that a committed polynomial evaluates to a claimed value at a specified point.
Opening claimThe polynomial identity being proved: a commitment, an opening point, and the claimed value.
Commitment groupOne or more related commitments that are opened together under one generated schedule.
Precommitted groupA commitment produced earlier and carried into a later grouped opening. Its profile is fixed when the commitment is created.
FoldOne step that replaces a large opening relation with a smaller one while preserving the claim the verifier must check.
Root foldThe first fold. It starts from the user's polynomial commitments and opening claims.
Recursive foldAn intermediate fold that consumes the relation produced by the preceding fold. A schedule may contain none.
Terminal foldThe final step, where the remaining witness is small enough to reveal and check directly.
Generated scheduleA precomputed choice of fold dimensions, bounds, opening methods, and proof layout for one supported request shape.
Catalog rowThe generated record selected for a particular configuration and group shape. The prover and verifier read the same row.
Proof shapeThe exact number, order, dimensions, and byte layout of every proof component required by a schedule.
Public setupPublic matrices and prepared data used to commit, prove, and verify. Akita does not require a secret trapdoor.
TranscriptThe ordered record of public inputs and proof messages from which Fiat-Shamir challenges are derived.
Base fieldThe field that stores committed coefficients and supports the lattice relation.
Extension fieldA larger field used for opening points, claimed evaluations, and transcript challenges in some configurations.
Cyclotomic ringThe quotient ring in which Akita's lattice commitments and fast polynomial arithmetic operate.
Dense polynomialA polynomial whose table positions may each contain an arbitrary field element.
One-hot polynomialA 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 decompositionWriting a field or ring value as a short vector of bounded signed digits in a power-of-two base.
Module-SISThe lattice assumption used to bind Akita commitments. Informally, it says that finding a short nonzero relation among the public commitment columns is hard.
Sum-checkAn interactive reduction that turns a sum over a Boolean cube into one polynomial evaluation at a random point.
Extension-opening reductionThe bridge from a base-field polynomial opened at an extension-field point to a packed extension-field polynomial with fewer variables.
Ring switchingAkita'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 offloadingCarrying 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

SymbolMeaning
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

SpecStatusWhy it remains live
akita-compute-backend-metalactiveMetal and hybrid backend work remains open.
composable-commitment-executionactiveDefines the current commitment source, backend composition, retained-state, and routing contracts while proving backend work remains open.
quotient-free-tail-ring-relationsactiveDefines reduced evaluation and its bounded quotient-free tail cutover.
quotient-free-tail-ring-relations-implementationactiveDefines the implementation architecture and acceptance contract for the quotient-free tail cutover.
dyadic-chunk-partitionimplementedDefines the current witness chunk partition contract.
family-agnostic-cpu-backendactiveDefines producer-catalog and proving-catalog ownership for one (F, E) backend, producer-contract provenance, and slot-keyed prefix persistence.
external-schedule-catalog-ownershipactiveOwns the in-flight cut from compiled schedule rows to explicitly supplied full-catalog artifacts.
guided-schedule-adaptationactiveDefines bounded offline adaptation from trusted scalar rows to exact grouped rows.
flat-public-matrix-and-exact-ntt-cacheimplementedLoad-bearing setup layout with follow-up provenance and artifact work.
fold-linf-rejectionimplementedIts sizing formula is used by the SIS cap implementation.
heterogeneous-group-source-contractsimplementedDefines current source-free group and fold-admission rules.
jolt-field-unificationactiveTracks the in-flight cutover to one shared Akita/Jolt field stack.
large-digit-ntt-infrastructureimplementedLoad-bearing large-digit NTT and terminal verification contract.
packed-sumcheckapprovedApproved packed EOR and sum-check implementation; earlier Stage 1 and Stage 2 prerequisite gates are complete.
role-native-projected-digit-layoutimplementedNormative witness and verifier layout source.
runtime-ring-cutoverimplementedNormative runtime ring contract cited by the architecture chapter.
selective-l2-fold-security-sizingimplementedCurrent security sizing source; deferred alternatives remain recorded.
setup-offloading-plannerimplementedCurrent recursive setup selection policy and external artifact contract.
sis-quantum128-scalar-n-tableimplementedCurrent 128-bit SIS security policy source.
structured-e-termimplementedCurrent structured verifier E-term contract.
subring-coefficient-packingactiveDefines packing relations, indexed fold challenges, and planner contracts. Its review record reports all three blockers repaired.
transcript-grindingimplementedDefines the current proof-of-work and fold-response grinding policy.
grinding-nonce-encodingactiveExplains 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

Multilinear polynomials and sum-check

Extension fields and packed openings

Post-quantum lattice standards

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 zk Cargo 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:

  1. It must define what is public and what remains private.
  2. It must account for every transcript message from the first commitment to the terminal check.
  3. It must preserve the range and norm bounds used by the binding proof.
  4. It must specify how the prover samples masks and what happens when sampling rejects.
  5. It must give the verifier one complete acceptance rule and reject malformed hiding data without panicking.
  6. 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)