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.
6.4 KiB
Spec 9: Aere entropy honesty fix — real drand BLS verification
The gap (what was dishonest)
aerenew/contracts/contracts/oracle/AereRandomnessBeacon.sol (live-deployed at
0x25b6317efD8C7d425210F56Ee1E204852CD8213C) shipped with a placeholder
verifier:
function _verify(uint64 /*round*/, bytes calldata /*signature*/) internal pure returns (bool) {
// Phase 2 implementation goes here.
return true;
}
It verified nothing. Worse, strictVerifyEnabled defaults to false, so even
that stub was never called: any bytes could be submitted as a "drand round". It
also derived randomness as keccak256(signature), which is NOT drand's
canonical randomness (SHA-256(signature)).
What I built
New files (the live beacon was NOT modified):
aerenew/contracts/contracts/oracle/AereRandomnessBeaconV2.sollibrary AereDrandQuicknetBLS— real BLS12-381 verification on EIP-2537:messageForRound=SHA-256(round as 8-byte big-endian)(quicknet is UNCHAINED)hashToField= RFC 9380expand_message_xmd(SHA-256, len 128) + reduce mod p via MODEXP. Uses only SHA-256 (0x02) + MODEXP (0x05), so it runs on any EVM.hashToG1= RFC 9380 SSWU_RO to G1 viaBLS12_MAP_FP_TO_G1(0x10) +BLS12_G1ADD(0x0b). (map already clears the cofactor, and cofactor clearing is a homomorphism, somap(u0)+map(u1)equals the RFC result.)decompressG1= zcash/ETH2 compressed-G1 decompression via MODEXP sqrt (p ≡ 3 mod 4, sqrt = a^((p+1)/4)); consumes drand's exact 48-byte sig.verifyRoundCompressed= pairing checke(H(m),pk) * e(sig,-G2) == 1viaBLS12_PAIRING_CHECK(0x0f).
contract AereRandomnessBeaconV2—submitRoundALWAYS verifies (no phase flag, no admin off-switch); stores canonicalSHA-256(signature)randomness.
aerenew/contracts/test/AereRandomnessBeaconV2.test.js— real drand vectors.aerenew/contracts/hardhat.config.prague.js— pins the localhardhatnetwork to thepraguehardfork so EIP-2537 is available for the full test.
Fail-closed everywhere: any wrong-length input, absent precompile (empty
returndata), wrong-length precompile output, non-square x, point at infinity, or
failed pairing resolves to false. There is no path that returns true without
a genuine pairing equality. When EIP-2537 is absent, verification returns
false and submitRound reverts (proven by the fail-closed-absence test).
drand chain targeted (pinned, not guessed)
League of Entropy quicknet, scheme bls-unchained-g1-rfc9380 (confirmed live
at api.drand.sh/<chainhash>/info):
- chain hash:
52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971 - public key (G2, 96-byte compressed):
83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a - period 3 s, genesis 1692803367, unchained, sigs on G1 / pubkey on G2
- hash-to-curve DST:
BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_
All scheme parameters were proven correct BEFORE writing Solidity, by
independently verifying genuine round 1000000 with @noble/curves (pairing of
H(m) against the pubkey equals pairing of the signature against the G2
generator → true; wrong round → false).
Real test vectors used (genuine, from api.drand.sh)
- round 1000000: sig
83ad29e4...abe72, randomnessb22aad47...440af3 - round 1000001: sig
a5bd91e5...c4218, randomness9f45f439...84ff(used as a valid-but-wrong-round negative case)
Confirmed on-chain: SHA-256(sig) reproduces the published randomness for both.
Test result (REAL, not [MEASURE])
Run from aerenew/contracts:
-
Default config (
cancun, no EIP-2537):npx hardhat test test/AereRandomnessBeaconV2.test.js-> 11 passing, 5 pending. Message reconstruction, RFC 9380 hash-to-field (matches @noble reference), G1 decompression (matches @noble reference), canonical randomness, input validation, and the fail-closed-absence checks all pass. The pairing cases correctly report[MEASURE]and skip because the precompiles are absent. -
Prague config (EIP-2537 live in the local EDR EVM):
npx hardhat test test/AereRandomnessBeaconV2.test.js --config hardhat.config.prague.js-> 15 passing, 1 pending. Full on-chain BLS verification:- hash-to-curve to G1 matches the independent @noble reference
- genuine round 1000000 verifies true; genuine round 1000001 verifies true
- valid signature submitted for the wrong round verifies false
- tampered signature verifies false
submitRound(1000000, genuineSig)stores randomness == publishedb22aad47...440af3; double-submit reverts; a non-verifying signature reverts fail-closed with no storage.
The local EDR EVM at the prague hardfork implements the same EIP-2537 spec that
is "Supported" on Aere mainnet (per docs/AERE-EIP-COMPATIBILITY-MATRIX.md), so
this is a genuine end-to-end pass of the on-chain verification logic.
Honest status
- This is a BUILT-AND-TESTED replacement, NOT a live swap. The deployed beacon was not touched. Activating V2 (or wiring real verification into the live contract) on Aere mainnet is founder-gated.
- [MEASURE, optional] A final confirmation run against the actual Aere mainnet RPC (chain 2800) would close the loop that mainnet's EIP-2537 matches the local EDR semantics. The compatibility matrix lists 2537 as Supported; the logic itself is proven locally on an EIP-2537 EVM.
- QUANTUM SCOPE: drand's BLS12-381 is CLASSICAL cryptography and is Shor-breakable. This fix makes the beacon actually verify what it stores (a correctness + honesty fix). It does NOT make the randomness post-quantum and is unrelated to Aere's PQC precompile track (Falcon/ML-DSA/SLH-DSA).
[VERIFY] flags
- None on the drand scheme parameters: the DST, message construction, and G1/G2 placement are all confirmed by the genuine round verifying true both in @noble/curves and in the on-chain pairing.
- The embedded
PUBKEY_G2andNEG_G2_GENERATORconstants are off-chain decompressions of, respectively, the canonical 96-byte compressed quicknet key and the standard BLS12-381 G2 generator. They are reproducible by anyone and are transitively validated by the passing pairing (a wrong pubkey/generator would make round 1000000 fail). Not a blocking [VERIFY], but flagged as a precomputed constant for an auditor to re-derive.