aere-docs/AERE-ENTROPY-BEACON-FIX.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

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.sol
    • library AereDrandQuicknetBLS — real BLS12-381 verification on EIP-2537:
      • messageForRound = SHA-256(round as 8-byte big-endian) (quicknet is UNCHAINED)
      • hashToField = RFC 9380 expand_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 via BLS12_MAP_FP_TO_G1 (0x10) + BLS12_G1ADD (0x0b). (map already clears the cofactor, and cofactor clearing is a homomorphism, so map(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 check e(H(m),pk) * e(sig,-G2) == 1 via BLS12_PAIRING_CHECK (0x0f).
    • contract AereRandomnessBeaconV2submitRound ALWAYS verifies (no phase flag, no admin off-switch); stores canonical SHA-256(signature) randomness.
  • aerenew/contracts/test/AereRandomnessBeaconV2.test.js — real drand vectors.
  • aerenew/contracts/hardhat.config.prague.js — pins the local hardhat network to the prague hardfork 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, randomness b22aad47...440af3
  • round 1000001: sig a5bd91e5...c4218, randomness 9f45f439...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:

  1. 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.

  2. 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 == published b22aad47...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_G2 and NEG_G2_GENERATOR constants 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.