Testing & guarantees
Testing baseline: fuzz coverage across five targets, cross-verification against published drand reference implementations, and a reproducible build SHA. Each claim below points to the artifact that backs it.
Testing covers the on-chain Anchor program (programs/alea-verifier/) at binary SHA 8965062489fdcdbb538597545fc6692f3f580d770d34f2d42000a70560984b1c. The same binary is deployed to devnet at ALEAydzHd4cN2EWcdHKp4hehAE4B88b16gqVtVqsck2U. Mainnet will deploy the same binary (or a superset with remediations applied) and the SHA will be published on deploy day.
The SDKs (alea-sdk Rust + @alea-drand/sdk TypeScript) are tested separately via unit tests in each crate.
Fuzzing
Section titled “Fuzzing”24 cumulative CPU-hours across five cargo-fuzz (libFuzzer) targets. Targets live at programs/alea-verifier/fuzz/fuzz_targets/. Ground truth for what each target actually exercises — below matches the source rather than what we’d like to be fuzzing:
| Target | What it fuzzes |
|---|---|
verify_beacon.rs | End-to-end verify pipeline with fuzzer-controlled (round, signature) pairs against EXPECTED_EVMNET_PUBKEY (pubkey is NOT fuzzed — Alea only verifies against drand evmnet). Invariant: the pipeline must never panic on any input. |
hash_to_g1.rs | SVDW hash-to-curve with two input shapes: Round(u64) and RawMessage(Vec<u8>) up to 1024 bytes. Invariants: no panic; if hash_to_g1 / hash_round_to_g1 returns Ok, the output must be on the BN254 G1 curve. |
on_curve_g1.rs | CVE-2025-30147 regression target. Runs Alea’s on_curve_g1 against an independent arkworks-based curve check on every 64-byte input and asserts byte-for-byte agreement. Catches any reordering of the canonical-form check against the curve-equation check. |
hash_to_field_canonicity.rs | RFC 9380 §5 canonicity of hash_to_field. Random 32-byte inputs; asserts both returned field elements are strictly below the BN254 modulus and round-trip to ≤32 canonical bytes. |
pairing_buffer_parses.rs | Panic-freedom on attacker-controlled G1 bytes for on_curve_g1 and negate_g1, plus the invariant that negation preserves curve membership. Does NOT invoke the pairing syscall — that path is covered by verify_beacon.rs end-to-end. |
Corpora seeded from real drand fixtures cross-imported from @kevincharm/noble-bn254-drand test vectors. Campaign artifacts (corpus directories + libFuzzer run logs) are archived locally; published release tarballs are on the roadmap. Ask via responsible disclosure if you need them for an independent review.
Cross-verification
Section titled “Cross-verification”Test vectors at drand rounds 1 and 9,337,227 cross-verified against three independent reference implementations:
| Reference | Location | Purpose |
|---|---|---|
@kevincharm/noble-bn254-drand | TypeScript, Noble Cryptography ecosystem | Primary cross-check against the Solidity-ancestor reference |
arkworks-rs/algebra | Rust | Academic-grade field / curve / pairing library |
| Drand REST API | https://api.drand.sh/<chain>/public/<round> | drand’s own published outputs |
All three agree with Alea on the 32-byte randomness (sha256(signature_bytes)) for both fixture rounds. Any divergence surfaces as a CI failure on every commit. Test source: verify.rs integration tests.
End-to-end verified on devnet
Section titled “End-to-end verified on devnet”| Test | Result |
|---|---|
| Drand round 1 (genesis evmnet) | Verifies on live devnet program, returns correct 32-byte randomness |
| Drand round 9,337,227 (arbitrary later round) | Same |
| Either round with any signature byte altered | Reverts with InvalidSignature (6000) |
| Config PDA content check | Stored evmnet group public key matches drand-published value |
Test files: sdk/rust/tests/devnet_verify.rs, sdk/typescript/tests/devnet_integration.test.ts.
Upgrade-and-redeploy continuity (preserving Config PDA across program upgrades) is a property consumers care about but is not covered by a repro-able CI test today. On the roadmap.
What has NOT been done
Section titled “What has NOT been done”No external third-party audit. No firm has formally reviewed the code — the testing baseline above is what exists, there is no audit report to cite, and mainnet will ship without one.
No formal verification. The pairing math is not mechanically proven. Alea relies on the correctness of ark-bn254 and Solana’s alt_bn128_pairing syscall.
No published coverage report. Line, branch, and mutation numbers haven’t been measured under a fixed toolchain; no lcov or mutants report in the repo. On the roadmap.
Also absent:
- Mainnet behavior under real load (Alea is not yet on mainnet)
- Constant-time characterization — the program’s signature operations use arkworks primitives, which haven’t been characterized for constant-time properties on Solana’s runtime. Side-channel attacks against an open
verify(round, signature)function are inherently low-impact (no secret to leak), but noted for completeness. - Adversarial drand-network tests. Testing assumes drand publishes honestly; a compromised drand federation is out of scope for any drand consumer.
Reproducing the build
Section titled “Reproducing the build”Deterministic given the pinned toolchain in repo root:
git clone https://github.com/alea-drand/aleacd alea# rust-toolchain.toml pins the toolchain; cargo-build-sbf uses its embedded rustccargo build-sbf --workspace --releasesha256sum target/deploy/alea_verifier.so# 8965062489fdcdbb538597545fc6692f3f580d770d34f2d42000a70560984b1cIf your hash differs, check rustc --version, cargo-build-sbf --version, and your Solana CLI version match the repo’s pinned toolchain. Non-deterministic builds would be worth a bug report.
Reproducing the fuzz runs
Section titled “Reproducing the fuzz runs”cd programs/alea-verifier/fuzzcargo +nightly fuzz run verify_beacon -- -max_total_time=3600cargo +nightly fuzz run hash_to_g1 -- -max_total_time=3600cargo +nightly fuzz run on_curve_g1 -- -max_total_time=3600cargo +nightly fuzz run hash_to_field_canonicity -- -max_total_time=3600cargo +nightly fuzz run pairing_buffer_parses -- -max_total_time=360024 cumulative CPU-hours across all five is the published baseline. Longer runs are welcome; new findings should be reported via responsible disclosure.
Related
Section titled “Related”- Security model — threat boundary
- Responsible disclosure — how to report findings
- Cluster addresses — canonical binary SHA, deploy tx