amashukov / cashaddr-php
CashAddr codec for Bitcoin Cash in pure PHP — BCH polymod checksum, base32, bitcoincash / bchtest / bchreg prefixes, P2PKH / P2SH / P2SH32 and token-aware CashTokens address types as a typed immutable value object.
Requires
- php: >=8.3
Requires (Dev)
- amashukov/rector-php-rules: ^0.4.1
- friendsofphp/php-cs-fixer: ^3.50
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- rector/rector: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
CashAddr codec for Bitcoin Cash in pure PHP — BCH polymod checksum, base32 payload, network prefixes and token-aware CashTokens address types as a typed immutable value object.
A CashAddr encoder / decoder for Bitcoin Cash written in plain PHP, with no runtime dependencies and no extensions. It implements the CashAddr specification — the 40-bit BCH polymod checksum over GF(2^5), the base32 alphabet, the version byte with its size bits — and the two token-aware address types added by CashTokens. Parsed addresses become a final readonly CashAddress value object that always prints in the normalized prefix:lowercase form, so two spellings of one address compare equal.
Features
- Spec-exact codec —
CashAddr::encode()/decode()handle every hash size the spec defines (160…512 bits) and any prefix;CashAddr::isChecksumValid()checks the polymod alone. - Typed address —
CashAddresscarries aCashAddrNetwork(bitcoincash,bchtest,bchreg), aCashAddrTypeand the raw hash. - Token-aware types as an enum —
P2PKH(q),P2SH(p),TokenAwareP2PKH(z),TokenAwareP2SH(r);isTokenAware()lets a caller refuse token addresses where it cannot handle them,plain()/tokenAware()convert between the pairs. - Prefix optional —
qr6m7j9n…is matched against the known networks by checksum, or against the one you pass. - Strict input — upper case is accepted, mixed case is rejected, a double prefix is rejected, padding bits must be zero, the version byte must match the payload length.
- Hash sizes per address type — 20 bytes for P2PKH, 20 or 32 bytes (P2SH32) for P2SH.
Installation
composer require amashukov/cashaddr-php
Usage
use Amashukov\CashAddr\CashAddress; use Amashukov\CashAddr\CashAddrException; use Amashukov\CashAddr\CashAddrNetwork; use Amashukov\CashAddr\CashAddrType; $address = CashAddress::fromString('QR6M7J9NJLDWWZLG9V7V53UNLR4JKMX6EYLEP8EKG2'); $address->network; // CashAddrNetwork::Mainnet $address->type; // CashAddrType::P2PKH $address->hashHex(); // 'f5bf48b397dae70be82b3cca4793f8eb2b6cdac9' $address->toString(); // 'bitcoincash:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eylep8ekg2' if ($address->type->isTokenAware()) { throw new DomainException('Token addresses are not accepted here.'); } CashAddress::fromString('bchtest:qr7fzmep8g7h7ymfxy74lgc0v950j3r295pdnvy3hr', CashAddrNetwork::Mainnet); // CashAddrException: CashAddr is for bchtest, bitcoincash expected. $tokenAware = $address->withType(CashAddrType::TokenAwareP2PKH); CashAddress::isValid('bitcoincash:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eylep8ekG2'); // false, mixed case
The lower layer works with any prefix and any spec hash size:
use Amashukov\CashAddr\CashAddr; $payload = CashAddr::decode('pref:pr6m7j9njldwwzlg9v7v53unlr4jkmx6ey65nvtks5'); $payload->prefix; // 'pref' $payload->type; // 1 CashAddr::encode('bchreg', 0, hex2bin('fc916f213a3d7f1369313d5fa30f6168f9446a2d'));
Test vectors
The suite runs every vector of the CashAddr specification (checksum vectors, legacy translation table, 160…512-bit payloads) and the CashTokens cashaddr.json set with the token-aware types, in both directions and in upper case.
Requirements
- PHP 8.3+ on a 64-bit build (the polymod state is 40 bits wide)
Related packages
| Package | Role |
|---|---|
| amashukov/bchn-rpc-client-php | Typed JSON-RPC client for Bitcoin Cash Node |
| amashukov/bitcoin-cash-php | Bitcoin Cash meta-package |
| amashukov/blockchain-address-php | Address value objects for EVM, TON and Lightning |
Quality
- PHPStan level 9, clean.
- php-cs-fixer
@PER-CSruleset. - GitHub Actions CI on every push.
License
MIT — see LICENSE.