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.
105 lines
5.9 KiB
Markdown
105 lines
5.9 KiB
Markdown
# Exporting a real SP1 v6.1.0 INNER STARK vector (for the PQ verifier KAT corpus)
|
|
|
|
> **SCOPE CORRECTION (2026-07-19 research finding; the premise below is wrong for the pinned SP1).**
|
|
> This document assumes SP1 6.1.0's inner proof is a BabyBear + Poseidon2 + FRI Plonky3 `ShardProof`.
|
|
> It is NOT. The pinned SP1 (facade `= "=6.1.0"`, internals `sp1-hypercube 6.3.1`) is a **Hypercube**
|
|
> release: its inner recursion proof is a **KoalaBear multilinear** proof (BaseFold + Jagged/Stacked
|
|
> PCS + sumcheck-zerocheck + LogUp-GKR with a septic-curve digest), with no BabyBear FRI `ShardProof`
|
|
> anywhere. So exporting a "shrink/compress Plonky3 shard proof over BabyBear + FRI" from SP1 6.1.0 is
|
|
> not possible: what SP1 6.1.0 exports is a Hypercube ShardProof (KoalaBear), which the BabyBear + FRI
|
|
> verifier skeleton does NOT verify. A real KAT corpus for the current skeleton must come from Aere's
|
|
> OWN Plonky3 (`zk-circuits/*`) BabyBear + FRI provers instead. Building a real SP1 6.1.0 corpus
|
|
> requires first retargeting 0x0AE8 to the SP1 Hypercube stack (a separate ~22 to 32 person-week
|
|
> effort). See `../../docs/AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC-SUMMARY.md` and
|
|
> `../../docs/AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC.md`. Read the instructions below with that in mind.
|
|
|
|
The PQ STARK-verify precompile (0x0AE8) verifies a BabyBear/Plonky3 **inner** hash-based FRI/STARK
|
|
proof directly, not a BN254 Groth16 wrap. Per the scope correction above, that BabyBear + FRI target
|
|
is Aere's own Plonky3 circuits, NOT the pinned SP1 6.1.0 (Hypercube). The steps below were written to
|
|
export a BabyBear + Poseidon2 + FRI "shrink"/compress shard proof; they apply to a BabyBear + FRI
|
|
Plonky3 prover, not to the SP1 6.1.0 Hypercube toolchain.
|
|
|
|
This file is instructions + a Rust snippet, NOT a bundled vector. As of 2026-07-18 **no real inner
|
|
vector is committed** here, because generating one requires running the SP1 prover (heavy; MUST be
|
|
on a throwaway non-infra box, never on the live infra host or a validator). Treat every "expect ACCEPT"
|
|
KAT as PENDING until a vector produced by this procedure is checked in.
|
|
|
|
## Provenance to pin
|
|
|
|
- SP1 `=6.1.0` (matches the repo's existing pins: `rollup-evm-validity/host/Cargo.toml`,
|
|
`batch-prover-recovered/bin/aere-prover/Cargo.toml`, `sp1-verifier = "=6.1.0"`).
|
|
- The proof object we want is the one BEFORE the Groth16/PLONK wrap:
|
|
- `SP1ReduceProof` after `prover.shrink(...)` (config 1, "inner/shrink"), and/or
|
|
- `SP1ReduceProof` after `prover.wrap_bn254(...)`'s *input* (config 2, "wrap"), i.e. the STARK
|
|
that Groth16 is about to attest, exported before the wrap.
|
|
- These are Plonky3 `ShardProof<BabyBearPoseidon2>` values. Their `serde`/`bincode` bytes are the
|
|
`friProof` body the precompile parses (spec doc section 3.2 pins the sub-layout to this exact
|
|
serialization + version).
|
|
|
|
## Rust snippet (run on a throwaway prover box)
|
|
|
|
```rust
|
|
// Cargo.toml: sp1-sdk = "=6.1.0", sp1-prover = "=6.1.0", bincode = "1.3", serde_json = "1"
|
|
use sp1_sdk::{ProverClient, SP1Stdin};
|
|
|
|
fn main() {
|
|
// A tiny guest ELF is enough for a KAT (e.g. the fibonacci example, or the aere-client guest).
|
|
let elf = std::fs::read("guest.elf").unwrap();
|
|
let client = ProverClient::from_env(); // CPU prover; native-gnark not needed for shrink
|
|
let (pk, vk) = client.setup(&elf);
|
|
|
|
let mut stdin = SP1Stdin::new();
|
|
stdin.write(&/* public input */ 20u32);
|
|
|
|
// 1) core proof -> 2) compress -> 3) shrink. Stop BEFORE groth16/plonk wrap.
|
|
let core = client.prove(&pk, &stdin).core().run().unwrap();
|
|
let compressed = client.prove(&pk, &stdin).compressed().run().unwrap();
|
|
// The inner API name varies by SP1 minor; in 6.1.0 the compressed proof carries the
|
|
// SP1ReduceProof. Serialize the reduce/shrink proof + vk + public values:
|
|
|
|
// vkey digest domain the precompile expects (Poseidon2 digest of the recursion vk):
|
|
let vkey_digest = vk.hash_babybear(); // [BabyBear; 8] -> 32 bytes big-endian per element pack
|
|
std::fs::write("sp1_shrink_vkeydigest.bin", pack_babybear8(&vkey_digest)).unwrap();
|
|
|
|
let public_values = compressed.public_values.to_vec();
|
|
std::fs::write("sp1_shrink_publicvalues.bin", &public_values).unwrap();
|
|
|
|
// The shard/reduce proof, bincode-serialized == the friProof body:
|
|
let proof_bytes = bincode::serialize(&compressed.proof).unwrap();
|
|
std::fs::write("sp1_shrink_proof.bin", &proof_bytes).unwrap();
|
|
|
|
// Also dump the FriConfig actually used (num_queries, log_blowup, pow_bits) so section 4 of the
|
|
// spec can pin configId 1 exactly instead of the placeholder values:
|
|
// println!("{:?}", <the shrink FriConfig>);
|
|
}
|
|
|
|
fn pack_babybear8(_x: &[u32; 8]) -> Vec<u8> { /* 4 BE bytes per limb -> 32 bytes */ vec![] }
|
|
```
|
|
|
|
## Assemble the precompile envelope
|
|
|
|
Concatenate into the v1 wire format the adapter/precompile expect (spec doc section 3):
|
|
|
|
```
|
|
magic("AS1\0") || version(1)=1 || configId(1)=1 || reserved(2)=0x0000
|
|
|| vkeyDigest(32) = sp1_shrink_vkeydigest.bin
|
|
|| publicValuesLen(4 BE) || publicValues = sp1_shrink_publicvalues.bin
|
|
|| proofLen(4 BE) || friProof = sp1_shrink_proof.bin
|
|
```
|
|
|
|
Name the file `vectors/sp1_shrink_valid_01.bin`. Produce the negatives by:
|
|
|
|
- `sp1_shrink_tampered_01.bin`: flip one byte inside a query-opening leaf of the proof (must REJECT).
|
|
- `sp1_shrink_wrongpub_01.bin`: mutate one byte of `publicValues` (must REJECT - the transcript
|
|
binds public values, so the sampled challenges diverge).
|
|
|
|
## What these vectors gate
|
|
|
|
Once the crypto core is ported (Poseidon2-BabyBear + FRI folding + SP1 recursion AIR), the KAT
|
|
corpus is the section-4 conformance gate in `docs/PQ-STARK-VERIFIER-ACTIVATION-2026-07-18.md`:
|
|
the precompile must ACCEPT every `*_valid_*` vector and REJECT every `*_tampered_*` / `*_wrongpub_*`
|
|
vector, plus a cross-check that the SAME public values verified through the live BN254 gateway
|
|
(0x9ca479...) and through 0x0AE8 agree on accept/reject. Until a real vector exists and the core is
|
|
ported, DO NOT claim the precompile verifies anything.
|
|
```
|