A PHP client for the drand distributed randomness beacon network (the League of Entropy), with cryptographic verification of the BLS12-381 threshold signatures.
drand-php is fail-closed: latest() and round() return a beacon only when
its signature verifies against the chain's distributed public key — otherwise
they throw. You never get unverified randomness by accident.
use Bmilleare\Drand\DrandClient;
$client = DrandClient::create($httpClient, $httpFactory, beaconId: 'quicknet');
$beacon = $client->latest(); // fetched AND verified
echo $beacon->round, PHP_EOL; // e.g. 29110875
echo $beacon->randomnessHex(), PHP_EOL; // 32-byte verifiable random value- Fetch randomness from any drand relay over the v2 (and v1) HTTP API.
- Verify BLS12-381 signatures for all three League-of-Entropy schemes.
- Two interchangeable verification backends behind one interface:
- blst — the audited supranational/blst C library via FFI (fast).
- pure-PHP — a dependency-free backend using
ext-gmp(portable).
- PSR-18 / PSR-17 transport: bring your own HTTP client (Guzzle, Symfony, ...) or use the bundled cURL client.
- Round/time helpers: compute the round at any timestamp and vice-versa.
- PHP 8.2+
ext-json,ext-curl(for the bundled HTTP client)- A verification backend (at least one):
ext-ffi+ alibblstshared library, orext-gmp(pure-PHP backend)
composer require bmilleare/drand-phpThe client refuses to run without a working verification backend (it throws
VerifierUnavailableException). Enable one:
Option A — blst (fast): enable ext-ffi and provide a libblst shared
library. Build it once:
php vendor/bmilleare/drand-php/bin/install-blst.php
# builds resources/lib/libblst.<so|dylib|dll>(or build blst yourself with
./build.sh -shared and point BlstVerifier at the resulting library).
Option B — pure-PHP (portable): install ext-gmp. No native library needed.
VerifierFactory::auto() prefers blst when available and falls back to pure-PHP.
use Bmilleare\Drand\DrandClient;
use Bmilleare\Drand\Http\CurlHttpClient;
use GuzzleHttp\Psr7\HttpFactory; // any PSR-17 factory
$factory = new HttpFactory();
$http = new CurlHttpClient($factory, $factory);
$client = DrandClient::create($http, $factory, beaconId: 'quicknet');
$beacon = $client->latest();
printf("round %d: %s\n", $beacon->round, $beacon->randomnessHex());$beacon = $client->round(29110875); // verified, or throws InvalidSignatureExceptionif ($client->verify($beacon)) {
// signature is valid
}$info = $client->chainInfo();
$round = $info->roundAt(time()); // current round number
$emittedAt = $info->timeOfRound($round);The League of Entropy mainnet runs these chains:
| Beacon | Scheme | Period | Signature | Public key | Message |
|---|---|---|---|---|---|
quicknet |
bls-unchained-g1-rfc9380 |
3s | G1 (48 B) | G2 (96 B) | sha256(round) |
default |
pedersen-bls-chained |
30s | G2 (96 B) | G1 (48 B) | sha256(prev‖round) |
quicknet is recommended for new applications: it is unchained (statelessly
verifiable) and has smaller, faster signatures. The randomness for every scheme
is sha256(signature).
- Fail-closed by design. The client never returns an unverified beacon. A
verification failure raises
InvalidSignatureException; an environment with no backend raisesVerifierUnavailableException. - Pin the chain hash / public key you expect for production use, and fetch chain info over a trusted channel — a malicious relay could otherwise serve a self-consistent fake chain.
- The blst backend uses an audited C library. The pure-PHP backend is a from-scratch implementation provided for portability; prefer blst where you can.
composer install
vendor/bin/phpunit # all tests (network tests skip if offline)
vendor/bin/phpunit --testsuite unit # offline onlyCryptographic correctness is pinned by tests that verify genuine captured beacons (positive vectors) and reject tampered ones (negative vectors).
MIT — see LICENSE.