aere-research/pq-stark/spec-poseidon2-constants.md
Aere Network 4a0b48588c 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:02:30 +03:00

7.3 KiB

Poseidon2-BabyBear (width 16) constants: provenance + conformance KAT (component (b), 0x0AE8)

Scope caveat (2026-07-19 finding). These BabyBear Poseidon2 constants come from Plonky3 0.4.3-succinct (Aere's OWN BabyBear + FRI STARK stack). They are NOT the pinned SP1 6.1.0's constants: SP1 6.1.0 is a Hypercube release over the KoalaBear field, so it uses KoalaBear Poseidon2 constants, not these. This component is conformance-confirmed for a BabyBear + FRI STARK verifier, not for an SP1 6.1.0 verifier. See ../../docs/AERE-STARK-SP1-RECURSION-AIR-PORT-SPEC-SUMMARY.md.

Date: 2026-07-19. Status: constants CONFIRMED-FROM-SOURCE; real conformance KAT PASSED.

This records exactly where every Poseidon2-BabyBear width-16 constant used by the PQ STARK-verify reference (component (b)) comes from, and the real known-answer test that confirms conformance. The top-level precompile 0x0AE8 stays fail-closed (returns EMPTY for every input) regardless: this component being confirmed does not port the sponge/FRI/MMCS/AIR.

Pinned target (exact, checksum-matched)

p3-baby-bear and p3-poseidon2, crates.io version 0.4.3-succinct (the Succinct Plonky3 fork), the revision pinned in the repo's Cargo.lock files:

  • p3-poseidon2 0.4.3-succinct, sha256 522986377b2164c5f94f2dae88e0e0a3d169cc6239202ef4aeb4322d60feffd0
  • p3-baby-bear 0.4.3-succinct, sha256 d69e6e9af4eaaaa60f7bb9f0e0f73ebcbaefe7e00974d97ad0fa542d6a4f0890

Found in aerenew/zk-circuits/*/Cargo.lock and aerenew/rollup-evm-validity/*/Cargo.lock. A fresh cargo build of the extractor (below) resolved the SAME two checksums, so the crates executed are byte-identical to the ones the AERE prover pins.

How the constants and KAT vectors were obtained (primary source)

The constants were NOT hand-transcribed. A small Rust extractor depending on the pinned crates was compiled and run (cargo 1.97.0), executing the actual library code:

  • Xoroshiro128Plus::seed_from_u64(1) (rand_xoshiro), then
  • Poseidon2::new_from_rng_128(Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, &mut rng) which samples external_constants: Vec<[BabyBear;16]> (8 rounds) then internal_constants: Vec<BabyBear> (13) via the library's own Distribution<BabyBear> for Standard,
  • and perm.permute_mut(...) on fixed inputs to emit known-answer vectors.

Each field element was printed as its canonical u32 via PrimeField32::as_canonical_u32(). The extractor also recovered the two linear-layer 16x16 matrices via basis-vector probes (see the Montgomery note). Machine-readable output: p3_ground_truth.json (constants + KATs) and p3_matrices.json (the two matrices) from the extractor run.

Corroborating source pages (structure only; the executed crates are authoritative for the numbers):

Confirmed parameters

  • Field: BabyBear p = 2^31 - 2^27 + 1 = 2013265921.
  • Width t = 16; S-box x^7 (7 = smallest d>1 with gcd(d, p-1)=1); ROUNDS_F = 8 (4+4), ROUNDS_P = 13.
  • External layer M_E: MDS-light block form from M4 = 2,3,1,1],[1,2,3,1],[1,1,2,3],[3,1,1,2 (diagonal blocks 2*M4, off-diagonal M4). Confirmed by recovering the exact 16x16 matrix from Poseidon2ExternalMatrixGeneral.
  • Internal diagonal D = INTERNAL_DIAG_M1_16 (canonical) = [p-2, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 32768].
  • 141 round constants (128 external + 13 internal), canonical; see the reference files (poseidon2_babybear_reference.py/.mjs, Poseidon2BabyBearSelfTest.java, Poseidon2Bb in the precompile) for the full literal arrays.

The Montgomery subtlety (the trap, resolved)

The internal linear layer DiffusionMatrixBabyBear, as a map on CANONICAL vectors, is NOT the textbook state[i] = state[i]*D[i] + sum. Recovering its exact 16x16 canonical matrix from the pinned library (basis-vector probes) showed every off-diagonal entry = 943718400 = R^{-1} = (2^32)^{-1} mod p, and diagonal I[i][i] = R^{-1}*(1 + D[i]) exactly. So:

M_I (canonical) = R^{-1} * (J + diag(D)),   i.e.   out[i] = R_INV * (sum + D[i]*state[i]),
R_INV = 943718400.

This R^{-1} is the Montgomery-form artifact (the library stores elements in Montgomery form, R = 2^32). A prior offline pass used the textbook state[i]*D[i] + sum (no R^{-1}); that is self-consistent and cross-language identical yet DISAGREES with the prover, exactly the "two wrong copies agree" trap. It is fixed. The external layer has no such factor (clean integer matrix), and round-constant addition + the x^7 S-box are unaffected by Montgomery form.

Conformance KAT (real known-answer vectors, executed from the pinned crates)

Emitted by perm.permute_mut(...) on the pinned library; reproduced EXACTLY by all three references (Python / Node / standalone Java) and by Poseidon2Bb in the precompile.

zeros in = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] out = [1787823396, 953829438, 89382455, 347481625, 1754527224, 916217775, 1056029082, 410644796, 1169123478, 1854704276, 1195829987, 1485264906, 1824644035, 1948268315, 847945433, 190591038]

iota in = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] out = [157639285, 1851003038, 1852457045, 1920360618, 779990819, 1080011039, 585017685, 1093051731, 249426030, 967262243, 623744062, 280332881, 1995600430, 1751988435, 317724737, 1895035071]

testvec (the p3-baby-bear width-16 test input) in = [894848333, 1437655012, 1200606629, 1690012884, 71131202, 1749206695, 1717947831, 120589055, 19776022, 42382981, 1831865506, 724844064, 171220207, 1299207443, 227047920, 1783754913] out = [512585766, 975869435, 1921378527, 1238606951, 899635794, 132650430, 1426417547, 1734425242, 57415409, 67173027, 1535042492, 1318033394, 1070659233, 17258943, 856719028, 1500534995]

Result (ran 2026-07-19):

  • python test_poseidon2_babybear.py -> PASS=47017 FAIL=0 (includes 3/3 conformance KATs; Python + Node + Java byte-identical; recorded in ../results/kat-results-poseidon2-babybear.json).
  • java Poseidon2BabyBearSelfTest -> PASS=13536 FAIL=0 (includes the 3 conformance KATs).

Status summary

  • Constants: CONFIRMED-FROM-SOURCE (executed the pinned crates; checksums matched Cargo.lock).
  • Conformance KAT: PASSED (3/3 real known-answer vectors reproduced byte-for-byte).
  • Poseidon2Bb.available = true (the permutation is confirmed conformant).
  • Top-level 0x0AE8: still FAIL-CLOSED (EMPTY for every input). The duplex-sponge challenger (Challenger.spongePorted = false), FRI folding, MMCS/Merkle openings, and the SP1 recursion-AIR are un-ported. DO NOT ACTIVATE.