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.
126 lines
6.4 KiB
Markdown
126 lines
6.4 KiB
Markdown
# 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:
|
|
|
|
```solidity
|
|
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 AereRandomnessBeaconV2` — `submitRound` 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.
|