Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
475 lines
32 KiB
Markdown
475 lines
32 KiB
Markdown
# AERE STARK verifier: SP1-recursion AIR port specification (precompile 0x0AE8, part 2)
|
|
|
|
Spec date: 2026-07-19
|
|
Status: RESEARCH + PORTING PLAN, not an implementation. This document scopes the ONE remaining
|
|
crypto-core piece of the native STARK-verify port (the SP1-recursion-specific constraint system and
|
|
its verifying key) against the REAL, pinned SP1 source. It does NOT port it. The top-level precompile
|
|
0x0AE8 stays fail-closed and is not touched by this document.
|
|
|
|
Companion: `docs/AERE-STARK-VERIFIER-PORT-SPEC.md` (the six generic components + their confirmed
|
|
status), `docs/PQ-STARK-VERIFIER-PRECOMPILE-2026-07-18.md` (design/encoding/gas),
|
|
`docs/PQ-STARK-VERIFIER-ACTIVATION-2026-07-18.md` (gated activation).
|
|
|
|
Citations use the pinned upstream tag `v6.1.0` (commit `d454975ac7c1126097e36eceda9bce2cb9899da4`,
|
|
github.com/succinctlabs/sp1). `[VERIFY]` marks a value or convention not read byte-exact from source in
|
|
this pass. `[MEASURE]` marks a validation that needs the compiled SP1 toolchain and a real proof.
|
|
|
|
---
|
|
|
|
## 0. Headline finding (read first): the pinned SP1 6.1.0 is Hypercube, not Turbo
|
|
|
|
This research turned up a correctness finding that changes the scope of the remaining work, so it goes
|
|
first and plainly.
|
|
|
|
The generic-component work in the companion spec was implemented and conformance-confirmed against
|
|
Plonky3 `0.4.3-succinct`: the BabyBear field, Poseidon2-over-BabyBear, a Merkle/MMCS, the FRI low-degree
|
|
test, a `p3-uni-stark` DEEP-ALI quotient check, and a `p3-challenger` duplex transcript. That is a
|
|
faithful BabyBear + FRI + univariate-STARK verifier skeleton, and it is real.
|
|
|
|
It is, however, the WRONG proof system for the version of SP1 that Aere actually pins. SP1 `=6.1.0`
|
|
(pinned in `rollup-evm-validity/host/Cargo.toml`, `rollup-evm-validity/guest/Cargo.toml`,
|
|
`batch-prover-recovered/bin/aere-prover/Cargo.toml`, all `sp1-sdk`/`sp1-prover`/`sp1-verifier`/`sp1-zkvm`
|
|
`= "=6.1.0"`) is an SP1 Hypercube release. Its proving stack is not AIR + FRI. It is a multilinear
|
|
system: KoalaBear field, a BaseFold + Stacked + Jagged polynomial commitment scheme, a sumcheck-based
|
|
constraint check (zerocheck), and a LogUp-GKR interaction argument with a degree-7 septic-curve global
|
|
cumulative digest. There is no BabyBear `ShardProof<BabyBearPoseidon2>` and no FRI low-degree test
|
|
anywhere in the SP1 6.1.0 proof that 0x0AE8 would verify.
|
|
|
|
Evidence, from both upstream source and the repo's own resolved lockfiles:
|
|
|
|
- Upstream `Cargo.toml` at tag v6.1.0 (`workspace.package.version = "6.1.0"`) lists workspace members
|
|
`slop/crates/{jagged, whir, basefold, sumcheck, multilinear, stacked, tensor, koala-bear, ...}` and
|
|
`sp1-gpu/crates/{jagged_sumcheck, logup_gkr, zerocheck, ...}`, and pins Plonky3 at `0.3.2-succinct`.
|
|
Source: https://github.com/succinctlabs/sp1/blob/v6.1.0/Cargo.toml
|
|
- `crates/primitives/src/lib.rs` defines `pub type SP1Field = KoalaBear;` and
|
|
`pub type SP1ExtensionField = BinomialExtensionField<SP1Field, 4>;` with `SP1GlobalContext =
|
|
KoalaBearDegree4Duplex` (Poseidon2 width 16, 30 total rounds).
|
|
Source: https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/primitives/src/lib.rs
|
|
- `crates/prover/src/recursion.rs` builds the compress/shrink/wrap recursion verifiers from
|
|
`RecursiveBasefoldVerifier` + `RecursiveMerkleTreeTcs` + `RecursiveStackedPcsVerifier` +
|
|
`RecursiveJaggedPcsVerifier` over `SP1Field`. There is no FRI verifier in that path.
|
|
Source: https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/prover/src/recursion.rs
|
|
- The repo's OWN resolved lock `rollup-evm-validity/host/Cargo.lock` (the crate that pins SP1 `=6.1.0`)
|
|
resolves `sp1-sdk 6.1.0`, `sp1-prover 6.1.0`, `sp1-verifier 6.1.0` on top of `sp1-hypercube 6.3.1`,
|
|
`sp1-recursion-machine 6.3.1`, `sp1-recursion-executor 6.3.1`, `slop-basefold 6.3.1`,
|
|
`slop-jagged 6.3.1`, `slop-multilinear 6.3.1`, `slop-sumcheck 6.3.1`. The SP1 6.1.0 facade crates sit
|
|
on the 6.3.1 Hypercube internals. The `p3-* 0.4.3-succinct` entries in the same lock (including
|
|
`p3-koala-bear`, `p3-fri`, `p3-uni-stark`) are Aere's own separate Plonky3 circuits' dependencies
|
|
(`zk-circuits/*`, the recursive-aggregation / zkml / attr provers), not the SP1 recursion proof.
|
|
|
|
Consequence for scope. The remaining work is not "add the SP1 AIR on top of a finished FRI skeleton."
|
|
It is "build a KoalaBear multilinear (BaseFold + Jagged + sumcheck + LogUp-GKR) machine verifier and
|
|
then add the SP1 recursion machine's chips on top." Of the six confirmed generic components, only the
|
|
SHAPES of three carry over (Poseidon2 sponge, Merkle tree, duplex challenger), and even those need the
|
|
KoalaBear field and the KoalaBear Poseidon2 constants. The two largest confirmed pieces, the FRI
|
|
low-degree test and the DEEP-ALI univariate quotient check, are not used by SP1 6.1.0 at all; they are
|
|
replaced by BaseFold and by sumcheck-zerocheck respectively. This is stated bluntly because it enlarges
|
|
the honest estimate (section 11) well beyond the companion spec's "3 to 4 person-weeks for the AIR."
|
|
|
|
Two clean options follow from this finding; both are out of scope to decide here but are named so the
|
|
founder can choose (section 13): retarget 0x0AE8 to the SP1 6.1.0 Hypercube recursion proof (the plan
|
|
below), or keep the existing BabyBear + FRI skeleton and point it at Aere's OWN Plonky3 STARKs (the
|
|
`zk-circuits/*` provers), which is a real but different capability and does not remove the SP1 BN254
|
|
Groth16 wrap.
|
|
|
|
Nothing in this document changes the fail-closed contract. On-chain ZK verification on Aere stays on the
|
|
classical BN254 Groth16 gateway (`0x9ca479C8c52C0EbB4599319a36a5a017BCC70628`) until the whole verifier
|
|
is real, KAT-green against a real exported SP1 proof, externally audited, and founder-activated.
|
|
|
|
---
|
|
|
|
## 1. Exact pinned version
|
|
|
|
| item | pin | source |
|
|
|---|---|---|
|
|
| SP1 facade crates | `sp1-sdk`, `sp1-prover`, `sp1-verifier`, `sp1-zkvm`, `sp1-build` `= "=6.1.0"` | `rollup-evm-validity/{host,guest}/Cargo.toml`, `batch-prover-recovered/**/Cargo.toml` |
|
|
| SP1 upstream tag | `v6.1.0`, commit `d454975ac7c1126097e36eceda9bce2cb9899da4` | github.com/succinctlabs/sp1 release v6.1.0 |
|
|
| SP1 recursion machine (resolved) | `sp1-hypercube 6.3.1`, `sp1-recursion-machine 6.3.1`, `sp1-recursion-executor 6.3.1` | `rollup-evm-validity/host/Cargo.lock` |
|
|
| PCS / sumcheck stack (resolved) | `slop-basefold 6.3.1`, `slop-jagged 6.3.1`, `slop-multilinear 6.3.1`, `slop-sumcheck 6.3.1` | `rollup-evm-validity/host/Cargo.lock` |
|
|
| rsp executor | git `succinctlabs/rsp` tag `reth-1.9.3-sp1-6.1.0` | `rollup-evm-validity/host/Cargo.toml` |
|
|
| field | `SP1Field = KoalaBear` (p = 2^31 - 2^24 + 1 = 2130706433 = 0x7F000001), ext degree 4 | `crates/primitives/src/lib.rs` @ v6.1.0 |
|
|
| Poseidon2 | width 16, 30 total rounds, `KoalaBearDegree4Duplex` | `crates/primitives/src/lib.rs` @ v6.1.0 |
|
|
|
|
Version-skew note `[VERIFY]`: the SP1 facade crates carry `6.1.0` while the recursion/PCS internals
|
|
resolve to `6.3.1`. The port must be pinned to the exact `sp1-recursion-machine` / `slop-*` `6.3.1`
|
|
revisions that the Aere lock resolves, not to a generic "6.1.0", because chip layouts and PCS parameters
|
|
can move between patch releases.
|
|
|
|
Reference implementation to follow (not a bundled dependency): Succinct's standalone
|
|
`github.com/succinctlabs/hypercube-verifier` (crates `algebra, basefold, commit, jagged, merkle-tree,
|
|
multilinear, stacked, sumcheck, tensor, stark, recursion, primitives, ...` plus a
|
|
`jagged-polynomial-commitments.pdf`). It is a clean, self-contained verifier for exactly this proof
|
|
system and is the best porting reference. Caveat `[VERIFY]`: its README marks it a research prototype as
|
|
of 2025-05-20, so its constants and shapes must be reconciled against the pinned `6.3.1` crates before
|
|
they are trusted byte-exact.
|
|
|
|
---
|
|
|
|
## 2. What 0x0AE8 would actually verify (the recursion / shrink / wrap proof shape)
|
|
|
|
The SP1 pipeline at v6.1.0 is: core RISC-V proof (`RiscvAir<SP1Field>`, Jagged PCS + LogUp-GKR +
|
|
sumcheck over KoalaBear) -> compress (recursively verify + fold shard proofs) -> shrink (compress to a
|
|
single small shard) -> wrap (re-prove under a BN254-friendly config) -> BN254 Groth16/PLONK. The only
|
|
Shor-breakable link is the final Groth16 wrap. The post-quantum replacement 0x0AE8 targets the proof
|
|
BEFORE that wrap: the shrink shard proof (configId 1) and/or the wrap-input shard proof (configId 2).
|
|
|
|
That proof is a `ShardProof` of the SP1 recursion machine (`RecursionAir` / `CompressAir`), verified by
|
|
`verify_shard`. Its shape, from `crates/hypercube/src/verifier/shard.rs` @ v6.1.0:
|
|
|
|
- `main_commitment`: Merkle (TCS) root over Poseidon2-KoalaBear of the main trace.
|
|
- `opened_values` (`ShardOpenedValues`): per-chip trace column evaluations at the sampled multilinear
|
|
point (there is no univariate zeta; evaluations are at a random point in the boolean-hypercube
|
|
extension domain).
|
|
- `zerocheck_proof`: the constraint sumcheck (point + claimed sum) that replaces the DEEP-ALI quotient.
|
|
- `logup_gkr_proof`: the LogUp-GKR interaction/lookup proof (per-chip evaluations).
|
|
- `evaluation_proof`: the Jagged / BaseFold PCS evaluation proof binding the opened values to the
|
|
commitment.
|
|
- `public_values`: the shard public values (for the recursion machine, `RecursionPublicValues`).
|
|
|
|
`verify_shard` steps (source order): observe public values and commitments into the Poseidon2-KoalaBear
|
|
challenger; validate proof shape against the machine config in the vk (chip counts, widths, heights);
|
|
verify the LogUp-GKR proof; verify the zerocheck proof (sample constraint-merging challenge `alpha`,
|
|
check merged constraint evaluations against the sumcheck claim, cross-check against the GKR evaluations);
|
|
verify the PCS opening via `jagged_pcs_verifier.verify_trusted_evaluations`; cross-check row counts and
|
|
the global cumulative sum. Source: https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/hypercube/src/verifier/shard.rs
|
|
|
|
The precompile wire format in `pqc-fork/pq-stark/export-inner-stark-vector.md` (magic `AS1\0`, version,
|
|
configId, vkeyDigest(32), publicValues, friProof) is broadly reusable, but two of its assumptions are
|
|
wrong for 6.1.0 and MUST be corrected: the body is a Hypercube `ShardProof` (bincode of the 6.3.1 type),
|
|
not a `ShardProof<BabyBearPoseidon2>`; and the vkey digest is `hash_koalabear()` packed (KoalaBear), not
|
|
`hash_babybear()`. See section 8.
|
|
|
|
---
|
|
|
|
## 3. Component map: what is done vs what this piece needs
|
|
|
|
| layer | confirmed generic skeleton (companion spec) | SP1 6.1.0 target (this spec) | reusable? |
|
|
|---|---|---|---|
|
|
| base field | BabyBear (0x78000001), F_{p^4}, W=11 | KoalaBear (0x7F000001), F_{p^4} | structure yes, constants NO |
|
|
| hash | Poseidon2-BabyBear, 8+13 rounds, 141 consts | Poseidon2-KoalaBear, 30 rounds | structure yes, constants NO |
|
|
| transcript | duplex challenger over BabyBear Poseidon2 | duplex over KoalaBear Poseidon2 | structure yes, re-field |
|
|
| vector commit | FieldMerkleTreeMmcs (Poseidon2) | Merkle TCS (Poseidon2-KoalaBear) | mostly yes |
|
|
| low-degree test | FRI fold + query (CONFIRMED) | BaseFold multilinear (sumcheck fold) | NO, different scheme |
|
|
| PCS wrapper | (FRI is the PCS) | Stacked + Jagged over BaseFold | NO, new |
|
|
| constraint check | DEEP-ALI univariate quotient (CONFIRMED) | zerocheck (sumcheck over merged constraints) | NO, different mechanism |
|
|
| interaction arg | none (out of generic scope) | LogUp-GKR + septic degree-7 global digest | NO, new, biggest specific add |
|
|
| machine AIR | example AIRs (Fibonacci, mul) | RecursionAir chip set (section 4) | NO, program-specific |
|
|
| vk binding | not on real path | KoalaBear Poseidon2 vk digest (section 8) | NO, new |
|
|
| public values | not on real path | RecursionPublicValues (section 9) | NO, new |
|
|
|
|
Reads as: the three "shape" rows (field, hash, transcript, merkle) port with a field swap plus new
|
|
constants; every other row is either a different scheme (BaseFold vs FRI, zerocheck vs DEEP-ALI) or an
|
|
entirely new component (Jagged, LogUp-GKR, the recursion chips, vk, public values).
|
|
|
|
---
|
|
|
|
## 4. The SP1 recursion machine AIR (RecursionAir): the chip set
|
|
|
|
`RecursionAir<F: PrimeField32 + BinomiallyExtendable<D>, const DEGREE, const VAR_EVENTS_PER_ROW>`, an
|
|
AIR machine derived with `sp1_derive::MachineAir`. Source:
|
|
https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/recursion/machine/src/machine.rs
|
|
Chip files: https://github.com/succinctlabs/sp1/tree/v6.1.0/crates/recursion/machine/src/chips
|
|
|
|
Full chip set (`machine_wide_with_all_chips`): `MemoryConst`, `MemoryVar`, `BaseAlu`, `ExtAlu`,
|
|
`Poseidon2Wide`, `Poseidon2LinearLayer`, `Poseidon2SBox`, `ExtFeltConvert`, `PrefixSumChecks`,
|
|
`Select`, `PublicValues`.
|
|
|
|
The two configs 0x0AE8 would verify use a subset:
|
|
|
|
- `compress_machine`: `MemoryConst`, `MemoryVar`, `BaseAlu`, `ExtAlu`, `Poseidon2Wide`,
|
|
`PrefixSumChecks`, `Select`, `PublicValues` (8 chips).
|
|
- `wrap_machine`: `MemoryConst`, `MemoryVar`, `BaseAlu`, `ExtAlu`, `Poseidon2LinearLayer`,
|
|
`Poseidon2SBox`, `ExtFeltConvert`, `Select`, `PublicValues` (9 chips; the wide Poseidon2 is split into
|
|
linear-layer + s-box chips for the BN254-friendly wrap).
|
|
|
|
Note the departure from SP1 Turbo: there is no `FriFold`, no `ExpReverseBitsLen`, and no `BatchFRI` chip
|
|
(those existed only because Turbo's recursion verified a FRI proof in-circuit). Their absence is itself
|
|
confirmation that the recursion layer no longer runs FRI. `PrefixSumChecks` and `ExtFeltConvert` are the
|
|
new arithmetic that the BaseFold/Jagged/sumcheck verification compiles down to.
|
|
|
|
Per-chip porting notes. For each chip the port must reproduce, in KoalaBear, its column layout and its
|
|
`eval()` constraint emission order exactly (a single mis-ordered or mis-filtered constraint makes the
|
|
folded constraint silently wrong):
|
|
|
|
- `MemoryConst`, `MemoryVar` (`chips/mem/`): the recursion VM's read/write memory tables; correctness of
|
|
addresses/timestamps is enforced through the interaction bus (section 5), so most of their weight is in
|
|
the LogUp argument, not local constraints. Constraint count per row: small (a handful) `[VERIFY]`.
|
|
- `BaseAlu` (`chips/alu_base.rs`), `ExtAlu` (`chips/alu_ext.rs`): field and extension-field add/sub/mul
|
|
(and the ext ALU carries F_{p^4} arithmetic). A few constraints each `[VERIFY]`.
|
|
- `Poseidon2Wide` / `Poseidon2LinearLayer` / `Poseidon2SBox` (`chips/poseidon2_wide/`,
|
|
`poseidon2_helper/`): the Poseidon2 permutation used inside the recursion VM (this is the in-circuit
|
|
hash the recursion program itself computes). Highest per-row constraint count of the set; the wide
|
|
variant is one row per permutation, the split variants spread it across rows for the wrap. Constraint
|
|
count: large (the dominant chip) `[VERIFY]`.
|
|
- `ExtFeltConvert` (`chips/`): base/extension felt conversion glue for the wrap.
|
|
- `Select` (`chips/select.rs`): conditional selection (multiplexer) constraints.
|
|
- `PrefixSumChecks` (`chips/prefix_sum_checks.rs`): running/prefix-sum constraints used by the
|
|
sumcheck/BaseFold verification the recursion program runs; medium constraint count `[VERIFY]`.
|
|
- `PublicValues` (`chips/public_values.rs`): binds the `RecursionPublicValues` (section 9) into the trace.
|
|
|
|
The overall `DEGREE` and `VAR_EVENTS_PER_ROW` const parameters and each chip's exact constraint count
|
|
were not read line-by-line in this pass and are `[VERIFY]` / `[MEASURE]`; the ground-truth method
|
|
(section 10) emits them directly from the compiled machine, which is the only trustworthy way to count
|
|
them (do not hand-estimate).
|
|
|
|
---
|
|
|
|
## 5. The interaction argument (LogUp-GKR + septic digest): the biggest specific addition
|
|
|
|
The chips do not talk to each other through shared columns; they talk through a multiset (lookup) bus
|
|
proved with LogUp-GKR, and this is the single largest component the generic quotient check does NOT
|
|
cover. Sources: `crates/hypercube/src/logup_gkr/` and `crates/hypercube/src/lookup/`,
|
|
`crates/hypercube/src/septic_{curve,digest,extension}.rs` @ v6.1.0.
|
|
|
|
Mechanism, as read from source:
|
|
|
|
- Every send/receive interaction a chip emits is reduced to a field element via a random linear
|
|
combination of the (kind, values) tuple with verifier challenges, then batched with the RLC challenge.
|
|
- The per-shard consistency of all sends and receives is proved with LogUp-GKR (a GKR circuit over the
|
|
rational LogUp identity), whose proof is `logup_gkr_proof` in the shard proof and is verified before
|
|
the zerocheck.
|
|
- The GLOBAL bus (cross-shard, e.g. memory that persists across the shard boundary) is accumulated into
|
|
a `SepticDigest`: a point on an elliptic curve defined over the degree-7 "septic" extension of
|
|
KoalaBear (`SepticExtension`, `[u32; 7]` coordinates). Each chip contributes a curve point; the digest
|
|
is a special offset-corrected cumulative sum
|
|
`start + sum_i (digest_i - offset) + offset - start` (the offset avoids Weierstrass addition
|
|
exceptions), with start/offset points derived from sqrt(2) and sqrt(3) constants
|
|
(`CURVE_CUMULATIVE_SUM_START_*`, `DIGEST_SUM_START_*`). The verifier checks the machine-level global
|
|
cumulative sum equals the expected value (for a complete proof, the buses net to the identity).
|
|
Source: https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/hypercube/src/septic_digest.rs
|
|
|
|
Why this is the hard part. Porting it faithfully requires: the exact interaction-kind enumeration and
|
|
field encoding per chip; the exact challenge-derivation order for the RLC and batching (a transcript
|
|
contract shared with the challenger); the full LogUp-GKR verifier (layer-by-layer sumcheck over the GKR
|
|
circuit); and the septic curve arithmetic (degree-7 extension mul, curve addition, the offset-sum
|
|
convention, the two magic start points). None of it exists in the confirmed skeleton, and any off-by-one
|
|
in the interaction encoding or the GKR layer order presents as a global "everything rejects" with no
|
|
localized error. The septic curve constants and the exact interaction encoding are `[VERIFY]` /
|
|
`[MEASURE]` (emit from the compiled machine).
|
|
|
|
---
|
|
|
|
## 6. The low-degree test: BaseFold (replaces FRI), plus Stacked + Jagged
|
|
|
|
FRI is not used. The PCS is a multilinear BaseFold committed over a Merkle TCS, wrapped by a Stacked PCS
|
|
(for batching columns of different heights) and a Jagged PCS (the "pay for what you use" evaluation
|
|
argument that reduces jagged, variable-length columns to a single multilinear evaluation via sumcheck).
|
|
Sources: `crates/prover/src/recursion.rs` (`RecursiveBasefoldVerifier`, `RecursiveMerkleTreeTcs`,
|
|
`RecursiveStackedPcsVerifier`, `RecursiveJaggedPcsVerifier`); reference crates
|
|
`hypercube-verifier/crates/{basefold, stacked, jagged, tensor, multilinear, sumcheck, merkle-tree}`.
|
|
|
|
What the port needs:
|
|
|
|
- BaseFold verifier: the multilinear analogue of FRI. Commit-phase folding driven by sumcheck rounds
|
|
(not the FRI fold relation), query openings against the Merkle TCS at each folded layer, final
|
|
evaluation check. The confirmed FRI `verify_query` does not apply; this is a new verifier.
|
|
- Stacked PCS: batches the per-chip column groups (different heights) into one commitment; the verifier
|
|
reconciles the per-group claims.
|
|
- Jagged PCS: `verify_trusted_evaluations` runs the jagged sumcheck that binds the opened multilinear
|
|
evaluations (`opened_values`) to the committed data at the sampled point. This is where the bulk of
|
|
the PCS soundness lives.
|
|
- Parameters (`[MEASURE]`): the BaseFold log_blowup / folding-arity / query count / proof-of-work bits
|
|
for the compress, shrink, and wrap configs, and the resulting soundness (score with the Hypercube
|
|
soundness analysis, not ethSTARK soundcalc, since this is not FRI). Whether the wrap config
|
|
(`CircuitWrapConfig`) uses different PCS parameters or a different field embedding than compress/shrink
|
|
is `[VERIFY]`.
|
|
|
|
---
|
|
|
|
## 7. The constraint check: zerocheck sumcheck (replaces DEEP-ALI quotient)
|
|
|
|
The confirmed generic quotient-consistency identity (`folded_constraints * inv_zeroifier == quotient`
|
|
from `p3-uni-stark`) is a UNIVARIATE-STARK mechanism and is not what SP1 6.1.0 checks. Instead the merged
|
|
AIR constraint is verified by a sumcheck (zerocheck): the verifier samples the constraint-merging
|
|
challenge `alpha`, the prover claims the merged constraint polynomial sums to zero over the boolean
|
|
hypercube, and the sumcheck reduces that claim to a single evaluation at a random point, which is then
|
|
opened through the PCS (section 6) and cross-checked against the LogUp-GKR evaluations. Source:
|
|
`crates/hypercube/src/verifier/shard.rs` verify step 4, and `hypercube-verifier/crates/stark/folder.rs`
|
|
+ `sumcheck`.
|
|
|
|
The port needs: the sumcheck verifier (round polynomials, challenge derivation, final-evaluation
|
|
reduction); the constraint folder that reproduces each chip's `eval()` emission order and its
|
|
first-row/last-row/transition filters in the multilinear setting; and the binding of the sumcheck's
|
|
final point to the PCS opening. The generic DEEP-ALI code is not reusable here beyond the high-level idea
|
|
of merging constraints with a random `alpha`.
|
|
|
|
---
|
|
|
|
## 8. The verifying key (vk) and its digest binding
|
|
|
|
`MachineVerifyingKey` fields (from `crates/hypercube/src/verifier/hashable_key.rs` @ v6.1.0):
|
|
`preprocessed_commit` (Merkle root of the preprocessed/selector trace), `pc_start`,
|
|
`initial_global_cumulative_sum` (a septic curve point, x and y), `enable_untrusted_programs`, plus the
|
|
machine shape (chip ordering, widths, heights) carried by the associated `Machine`. Source:
|
|
https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/hypercube/src/verifier/hashable_key.rs
|
|
|
|
Digest binding. `HashableKey` provides `hash_koalabear()` (Poseidon2 over KoalaBear of
|
|
`[preprocessed_commit, pc_start, initial_global_cumulative_sum.x, initial_global_cumulative_sum.y,
|
|
enable_untrusted_programs]`, producing an 8-element SP1Field digest), `hash_u32()`, `hash_bytes()`, and
|
|
`hash_bn254()` (via `koalabears_to_bn254()`, the digest the on-chain Groth16 path currently binds).
|
|
|
|
For 0x0AE8 the verifier must (a) recompute `hash_koalabear()` over the supplied vk fields, (b) check it
|
|
equals the 32-byte `vkeyDigest` in the AS1 wire envelope, and (c) use the vk's machine shape to drive the
|
|
shape checks in `verify_shard`. The export doc's `vk.hash_babybear()` is WRONG for 6.1.0 and must be
|
|
`hash_koalabear()`; the packing is 8 KoalaBear limbs, big-endian per limb. `[VERIFY]` the exact limb
|
|
order and the exact field list that feeds `hash_koalabear` at the pinned 6.3.1 revision.
|
|
|
|
---
|
|
|
|
## 9. The public-values layout
|
|
|
|
`RecursionPublicValues<T>` (from `crates/recursion/executor/src/public_values.rs` @ v6.1.0), field type
|
|
KoalaBear (`T = SP1Field`) on the real path. Fields (source order, as read):
|
|
`prev_committed_value_digest`, `committed_value_digest`, `prev_deferred_proofs_digest`,
|
|
`deferred_proofs_digest`, `pc_start`, `next_pc`, `initial_timestamp`, `last_timestamp`, memory/page
|
|
indices, `sp1_vk_digest`, `vk_root`, `global_cumulative_sum` (septic point), `digest`, `proof_nonce`,
|
|
`contains_first_shard`, `num_included_shard`, `is_complete`, `exit_code`, `commit_syscall`,
|
|
`commit_deferred_syscall`. Total element count is `RECURSIVE_PROOF_NUM_PV_ELTS =
|
|
size_of::<RecursionPublicValues<u8>>()`; the exact integer is `[VERIFY]` (emit from the compiled crate).
|
|
Source: https://github.com/succinctlabs/sp1/blob/v6.1.0/crates/recursion/executor/src/public_values.rs
|
|
|
|
The verifier must: parse these from the wire `publicValues`; observe them into the challenger in the
|
|
exact source order (they bind the transcript, so a wrong order diverges every challenge); check the
|
|
internal `digest` consistency; and expose `committed_value_digest` / `sp1_vk_digest` / `vk_root` /
|
|
`is_complete` / `exit_code` as the verified outputs the AerePQStarkVerifier adapter returns. The
|
|
committed-value digest and `sp1_vk_digest` are what a caller uses to bind a specific guest program and
|
|
its output, exactly as the BN254 path does today.
|
|
|
|
---
|
|
|
|
## 10. Ground-truth method (the only trustworthy validation)
|
|
|
|
Every constraint count, parameter, and layout marked `[VERIFY]` / `[MEASURE]` above must be produced from
|
|
the compiled pinned toolchain, never hand-derived. The method, on a throwaway non-infra prover box (never
|
|
the live infra host, never a validator; see the no-heavy-compute-on-infra rule):
|
|
|
|
1. Pin a Rust workspace to the exact resolved revisions in `rollup-evm-validity/host/Cargo.lock`:
|
|
`sp1-sdk = "=6.1.0"`, and let it resolve `sp1-hypercube`, `sp1-recursion-machine`,
|
|
`sp1-recursion-executor`, `slop-basefold`, `slop-jagged`, `slop-multilinear`, `slop-sumcheck` at
|
|
`6.3.1`. Vendor them for reproducibility.
|
|
2. Emit machine metadata directly: for `compress_machine()` and `wrap_machine()`, print each chip's name,
|
|
width, and its symbolic constraint count and max degree; print `RECURSIVE_PROOF_NUM_PV_ELTS`; print the
|
|
BaseFold/Jagged config parameters; print the septic curve constants and the interaction-kind encoding.
|
|
This replaces every `[VERIFY]` count with a measured one.
|
|
3. Produce a real proof: run a tiny guest (fibonacci or `aere-client`) through
|
|
`prove(...).compressed()`, stopping before the Groth16 wrap; serialize the shrink `ShardProof`
|
|
(bincode), the vk, and its `hash_koalabear()` digest and `public_values`. This is the
|
|
`sp1_shrink_valid_01.bin` corpus vector (correcting the export doc to KoalaBear + Hypercube).
|
|
4. Instrument `verify_shard` to dump the exact challenger transcript (observe order, sampled `alpha`, the
|
|
sumcheck points, the query indices) so each ported sub-verifier can be diffed byte-for-byte against
|
|
the reference, the same KAT discipline the generic components used.
|
|
|
|
Follow the `hypercube-verifier` reference crate structure (section 1) so the port is a
|
|
component-by-component mirror of a maintained verifier, not a from-scratch reading of the prover.
|
|
|
|
---
|
|
|
|
## 11. Effort, hardest parts, honest estimates
|
|
|
|
Realistic single-specialist estimates (STARK/sumcheck specialist with the SP1 toolchain). These are
|
|
deliberately not optimistic; the two generic pieces the companion spec counted as done (FRI, DEEP-ALI)
|
|
do not carry over, so the remaining surface is larger than that spec's "3 to 4 weeks for the AIR."
|
|
|
|
| piece | effort (person-weeks) | risk |
|
|
|---|---|---|
|
|
| KoalaBear field + F_{p^4} (re-field the confirmed BabyBear code, new prime/constants) | ~0.5 to 1 | low |
|
|
| Poseidon2-KoalaBear (width 16, 30 rounds, new constants) + duplex challenger re-field | ~1 to 1.5 | medium (constants) |
|
|
| Merkle TCS over KoalaBear (re-field the confirmed MMCS) | ~0.5 to 1 | low |
|
|
| BaseFold multilinear verifier (new, replaces FRI) | ~3 to 4 | high |
|
|
| Stacked + Jagged PCS verifier (new, the jagged sumcheck) | ~3 to 4 | high |
|
|
| sumcheck + zerocheck constraint check (new, replaces DEEP-ALI) | ~2 to 3 | high |
|
|
| LogUp-GKR + septic degree-7 global digest (new, biggest specific add) | ~3 to 4 | HARDEST |
|
|
| RecursionAir chip constraints (8 to 11 chips, KoalaBear, exact eval order) | ~3 to 4 | high |
|
|
| vk binding (`hash_koalabear`) + RecursionPublicValues + shape checks | ~1 to 2 | medium |
|
|
| wire parser (`WireReader` for the Hypercube ShardProof) + adapter wiring | ~1 to 2 | medium |
|
|
| integration, gas benchmark under EIP-7825, KAT corpus, soundness scoring, audit prep | ~4 to 6 | high |
|
|
| total | ~22 to 32 person-weeks | multi-month |
|
|
|
|
That is roughly 5 to 8 months of focused single-specialist work plus an external audit, materially more
|
|
than the companion spec's figure because the target is Hypercube, not Turbo. Hardest parts, ranked:
|
|
(1) LogUp-GKR + septic digest interaction argument (section 5); (2) BaseFold + Jagged PCS (section 6);
|
|
(3) the sumcheck zerocheck constraint mechanism (section 7); (4) the RecursionAir chips at exact eval
|
|
order (section 4). Each is multi-week on its own.
|
|
|
|
Given this, the design doc's recommendation (companion spec section 5.1) is even more compelling: wrap a
|
|
pinned, reproducible NATIVE build of the maintained Rust verifier (the `hypercube-verifier` crates or the
|
|
`sp1-verifier 6.1.0` inner path) as the precompile's crypto core, rather than hand-port a KoalaBear
|
|
BaseFold + Jagged + sumcheck + LogUp-GKR verifier into Java. A hand port multiplies the audit surface and
|
|
the "two wrong copies agree" risk across every one of the pieces above.
|
|
|
|
---
|
|
|
|
## 12. End-to-end conformance KAT (the final gate)
|
|
|
|
The single test that proves the whole verifier, once the pieces above exist:
|
|
|
|
1. Export a real SP1 6.1.0 shrink (configId 1) and wrap-input (configId 2) proof + vk + public values by
|
|
the section-10 method; wrap each into the AS1 envelope (KoalaBear `hash_koalabear` vkey digest).
|
|
2. `sp1_shrink_valid_01.bin`, `sp1_wrap_valid_01.bin`: 0x0AE8 must ACCEPT (return the verified
|
|
committed-value digest / vk digest), and the SAME public values verified through the live BN254
|
|
gateway (`0x9ca479...`) must agree on accept.
|
|
3. Negatives, each must REJECT (return EMPTY): flip one byte inside a query opening
|
|
(`*_tampered_*`); mutate one byte of `publicValues` (`*_wrongpub_*`, the transcript binds them);
|
|
swap in a vk with a different `hash_koalabear` digest (`*_wrongvk_*`); tamper one sumcheck round
|
|
polynomial and one LogUp-GKR layer (`*_badsumcheck_*`, `*_badgkr_*`).
|
|
4. Cross-field regression: the confirmed BabyBear + FRI skeleton must continue to reject these KoalaBear
|
|
Hypercube inputs (it is a different verifier), confirming the two are not conflated.
|
|
|
|
Until a real exported SP1 6.1.0 proof exists and passes this, the precompile verifies nothing and stays
|
|
fail-closed. There is no offline substitute for this KAT.
|
|
|
|
---
|
|
|
|
## 13. Bottom line for the whole #2 effort
|
|
|
|
- What is real today: a BabyBear + FRI + univariate-STARK verifier SKELETON with six conformance-confirmed
|
|
generic components (field, Poseidon2, MMCS, FRI, transcript, DEEP-ALI quotient) against Plonky3
|
|
`0.4.3-succinct`. That is genuine, tested work, and it is the correct verifier for Aere's OWN Plonky3
|
|
STARKs (`zk-circuits/*`).
|
|
- What is NOT true: that this skeleton is most of an SP1 6.1.0 verifier. SP1 6.1.0 is Hypercube. Its
|
|
inner recursion proof is a KoalaBear multilinear proof (BaseFold + Stacked + Jagged PCS, sumcheck
|
|
zerocheck, LogUp-GKR with a degree-7 septic global digest) over the `RecursionAir` chip set. The FRI
|
|
and DEEP-ALI pieces do not apply to it; only the Poseidon2/Merkle/challenger SHAPES carry over, and
|
|
those need the KoalaBear field and constants.
|
|
- What stands between here and a live native post-quantum STARK verifier that replaces the classical
|
|
BN254 Groth16 gateway: (1) a KoalaBear re-field of the shape components; (2) the four new components
|
|
(BaseFold, Jagged/Stacked, sumcheck-zerocheck, LogUp-GKR + septic digest); (3) the RecursionAir chips;
|
|
(4) the vk binding and RecursionPublicValues; (5) a real exported SP1 6.1.0 end-to-end proof KAT; (6)
|
|
soundness scoring and an EIP-7825 gas benchmark; (7) an external audit; (8) founder activation.
|
|
- Realistic total remaining: on the order of 22 to 32 person-weeks (roughly 5 to 8 months) of a
|
|
STARK/sumcheck specialist plus an external audit, whether hand-ported or (recommended) wrapped as a
|
|
pinned native build of the maintained Rust verifier. The top-level 0x0AE8 stays fail-closed the entire
|
|
time; on-chain ZK verification remains classical BN254 Groth16 until all eight gates are met and the
|
|
founder activates.
|
|
|
|
---
|
|
|
|
## 14. Open `[VERIFY]` / `[MEASURE]` flags
|
|
|
|
1. `[VERIFY]` Version skew: pin the exact `sp1-recursion-machine` / `slop-* 6.3.1` revisions the Aere
|
|
lock resolves; the `6.1.0` facade sits on `6.3.1` internals.
|
|
2. `[VERIFY]/[MEASURE]` Per-chip constraint counts, `DEGREE`, `VAR_EVENTS_PER_ROW` (emit from the
|
|
compiled machine, section 10).
|
|
3. `[VERIFY]/[MEASURE]` `RECURSIVE_PROOF_NUM_PV_ELTS` exact integer and the exact PV field ordering.
|
|
4. `[VERIFY]/[MEASURE]` BaseFold / Jagged parameters (blowup, folding arity, query count, pow bits) for
|
|
compress, shrink, and wrap; whether `CircuitWrapConfig` differs.
|
|
5. `[VERIFY]/[MEASURE]` Septic curve constants (a, b, sqrt(2)/sqrt(3) start points) and the exact
|
|
per-chip interaction-kind encoding + challenge order.
|
|
6. `[VERIFY]` Exact `hash_koalabear()` input field list and limb packing at 6.3.1.
|
|
7. `[VERIFY]` KoalaBear Poseidon2 external/internal round split within the 30 total rounds, and its
|
|
constants.
|
|
8. `[VERIFY]` Exact-constant conformance of the `hypercube-verifier` reference (2025-05-20 prototype)
|
|
against the pinned 6.3.1 crates.
|
|
9. `[MEASURE]` The end-to-end KAT (section 12): needs a real exported SP1 6.1.0 proof; nothing offline
|
|
substitutes for it.
|
|
|
|
## 15. Files
|
|
|
|
- `docs/AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC.md` (this document).
|
|
- `docs/AERE-STARK-VERIFIER-PORT-SPEC.md` (the generic skeleton + its confirmed status; note its
|
|
BabyBear/FRI premise for SP1 6.1.0 is corrected here).
|
|
- `pqc-fork/pq-stark/export-inner-stark-vector.md` (real-vector export; correct `hash_babybear` ->
|
|
`hash_koalabear` and the ShardProof type to the Hypercube 6.3.1 type per section 8).
|
|
- `pqc-fork/precompiles/Sp1StarkVerifierPrecompiledContract.java` (fail-closed skeleton; unchanged).
|
|
- `contracts/contracts/zkverify/AerePQStarkVerifier.sol` (fail-closed adapter; unchanged).
|