aere-docs/AERE-STARK-POSEIDON2-CONSTANTS-CONFIRMED.md
Aere Network e4cead319d Initial public release
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.
2026-07-20 01:01:36 +03:00

78 lines
4.8 KiB
Markdown

# Poseidon2-BabyBear width-16 constants: confirmation + conformance (task summary)
> **Scope caveat (2026-07-19 finding).** These constants are confirmed against Plonky3
> `0.4.3-succinct` (Aere's OWN BabyBear + FRI STARK stack), NOT against SP1 6.1.0. SP1 6.1.0 is a
> **Hypercube** release over the **KoalaBear** field, so these BabyBear Poseidon2 constants are not
> SP1 6.1.0's constants, FRI and DEEP-ALI do not apply to SP1 6.1.0, and this work does not verify SP1
> 6.1.0 proofs. Replacing the SP1 BN254 Groth16 wrap is a separate ~22 to 32 person-week retarget.
> See `AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC-SUMMARY.md`.
Date: 2026-07-19. Component (b) of the PQ STARK-verify precompile 0x0AE8.
## Outcome (headline)
- Constants: **CONFIRMED-FROM-SOURCE.**
- Conformance KAT: **PASSED** (3/3 real known-answer vectors reproduced byte-for-byte).
- Top-level 0x0AE8: **still fail-closed** (returns EMPTY for every input). DO NOT ACTIVATE banner kept.
## What the prior pass had wrong, and what was confirmed
The prior pass implemented the permutation STRUCTURE but used SHA-256 PLACEHOLDER round constants
(`AERE-PLACEHOLDER-NOT-PLONKY3`) and a textbook internal layer. Two things were confirmed/fixed:
1. The 141 round constants are now the real Plonky3 values (128 external + 13 internal), generated by
`Xoroshiro128Plus::seed_from_u64(1)` via `new_from_rng_128` and extracted from the pinned crates.
2. The internal linear layer was WRONG (a genuine bug, the "two wrong copies agree" trap). The pinned
`DiffusionMatrixBabyBear`, as a canonical map, is `M_I = R^{-1} * (J + diag(D))` with
R^{-1} = 943718400 = (2^32)^{-1} mod p, i.e. `out[i] = R_INV*(sum + D[i]*state[i])`. The prior pass
used `state[i]*D[i] + sum` (no R^{-1}), which is self-consistent but disagrees with the prover.
This is the Montgomery-form subtlety the task flagged. Verified by recovering the exact 16x16
canonical matrix from the library (off-diagonal = R^{-1}, diagonal = R^{-1}*(1+D[i])).
Also confirmed: ROUNDS_F=8, ROUNDS_P=13 (`poseidon2_round_numbers_128(16,7)`); M4 =
[[2,3,1,1],[1,2,3,1],[1,1,2,3],[3,1,1,2]] (recovered from `Poseidon2ExternalMatrixGeneral`); the
internal diagonal D = [p-2,1,2,4,...,8192,32768] (canonical). The x^7 S-box was already solid.
## Source (exact) and method
Pinned target: `p3-baby-bear` / `p3-poseidon2` crates.io `0.4.3-succinct` (checksums
`d69e6e9a...` / `52298637...`, matching `aerenew/.../Cargo.lock`). The numbers are authoritative
because the pinned crates were compiled and executed (cargo 1.97.0; the fresh build resolved the same
two checksums, byte-identical to the AERE pin). Corroborating source pages:
- https://docs.rs/crate/p3-baby-bear/0.4.3-succinct/source/src/poseidon2.rs (diagonal, RNG comment)
- https://docs.rs/crate/p3-monty-31/0.4.3-succinct/source/src/monty_31.rs (Standard sampling, new_monty)
- https://docs.rs/crate/p3-poseidon2/0.4.3-succinct/source/src/lib.rs (new_from_rng_128 order)
- https://github.com/Plonky3/Plonky3 poseidon2/src/{round_numbers.rs, external.rs}
- https://github.com/rust-random/rngs rand_xoshiro (SplitMix64 seed, next_u32 = next_u64>>32)
Full provenance + the KAT vectors: `aerenew/pqc-fork/pq-stark/spec-poseidon2-constants.md`.
## Conformance KAT (executed from the pinned library, reproduced by all references)
- zeros [0;16] -> [1787823396, 953829438, 89382455, ...]
- iota [0..15] -> [157639285, 1851003038, 1852457045, ...]
- testvec (p3 test) -> [512585766, 975869435, 1921378527, ...]
Results: `python test_poseidon2_babybear.py` -> PASS=47017 FAIL=0 (Python/Node/Java byte-identical,
3/3 conformance KATs); `java Poseidon2BabyBearSelfTest` -> PASS=13536 FAIL=0.
## Files changed
- `aerenew/pqc-fork/pq-stark/poseidon2_babybear_reference.py` / `.mjs` — real constants, R_INV
internal layer, conformance KATs.
- `aerenew/pqc-fork/pq-stark/Poseidon2BabyBearSelfTest.java` — same; self-test PASS=13536.
- `aerenew/pqc-fork/pq-stark/test_poseidon2_babybear.py` — added conformance stage; honest status.
- `aerenew/pqc-fork/precompiles/Sp1StarkVerifierPrecompiledContract.java` — real constants, R_INV
internal layer, `Poseidon2Bb.available = true`; decoupled challenger gate
(`Challenger.spongePorted = false`) so the top level stays fail-closed.
- `aerenew/pqc-fork/pq-stark/README.md`, `aerenew/docs/AERE-STARK-VERIFIER-PORT-SPEC.md` — real status.
- New: `aerenew/pqc-fork/pq-stark/spec-poseidon2-constants.md` (provenance/citation doc).
## Fail-closed confirmation
`Poseidon2Bb.available = true` (permutation confirmed), but the duplex sponge is a separate un-ported
component: `Challenger.spongePorted = false` -> `checkProofOfWork` returns false and
`sampleQueryIndices` returns empty; `StarkConstraints.evaluateAtZeta` and `Fri.checkQuery` return
UNAVAILABLE. So `verify(...)` never reaches `return ACCEPT`; the precompile returns EMPTY for every
input. The DO NOT ACTIVATE banner is intact.