- PHP 5.4+
- Composer
- ext-gmp
- ext-mcrypt
- [secp256k1-php] - Install the secp256k1 PHP extension for blazing speeds.
- [bitcoinconsensus-php] - Install libbitcoinconsensus for script validation
##Installation
You can install this library via Composer:
composer require bitwasp/bitcoin
or
"require": "bitwasp/bitcoin"
}```
##Presently supported:
- Blocks, block headers, basic mining, difficulty calculations
- P2SH, Multisignature scripts.
- ECDSA key creation, public & private key types.
- Transactions
- Signature creation & verification
- Deterministic signatures (RFC6979)
- BIP32 deterministic algorithms
- Script builder for common input/output types, parser, interpreter.
- Supports bindings to libsecp25k61 and libbitcoinconsensus.
- RPC bindings to Bitcoin Core's RPC, getting OOP responses
- Bindings to Stratum (electrum) servers
- Easy serialization to binary representation of most classes
- SIGHASH types when creating transactions (not tested)
- Payment Protocol (BIP70)
- Peer-to-peer protocol
- Blockchain classes utilizing the doctrine/cache package
##Known Issues:
The script interpreter has a modest set of test vectors, but these are mostly positive tests, that don't really exercise many of the edge cases. While it works, it's not bug-for-bug compatible yet and should not be relied on for consensus.
Similarly, the secp256k1-php extension is a wrapper around an experimental library which has not yet been formally released. It's use should not be relied on until the upstream library has made a stable release.
##Todo:
- SPV
## Implemented BIPs
- BIP0011
- BIP0016
- BIP0032
- BIP0039
- BIP0066
- BIP0067
- BIP0070
# Examples
## Generate private keys
```php
// Create private keys
use BitWasp\Bitcoin\Key\PrivateKeyFactory;
$network = Bitcoin::GetNetwork();
$private = PrivateKeyFactory:create(true);
$public = $private->getPublicKey();
echo $private->getBuffer() . "\n";
echo $public->getBuffer() . "\n";
echo $public->getAddress($network) . "\n";
use BitWasp\Bitcoin\Rpc\RpcFactory;
$bitcoind = RpcFactory::bitcoind('127.0.0.1', 18332, 'bitcoinrpc', 'BBpsLqmCCx7Vp8sRd5ygDxFkHZBgWLTTi55QwWgN6Ng6');
$hash = $bitcoind->getbestblockhash();
$block = $bitcoind->getblock($hash);
$tx = $bitcoind->getTransactions()->getTransaction(10);
echo $tx->getTransactionId();
use BitWasp\Bitcoin\Address\AddressFactory;
use BitWasp\Bitcoin\PaymentProtocol\PaymentRequestBuilder;
use BitWasp\Bitcoin\PaymentProtocol\PaymentRequestSigner;
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Transaction\TransactionOutput;
$time = time();
$amount = 10000;
$destination = '18Ffckz8jsjU7YbhP9P44JMd33Hdkkojtc';
$paymentUrl = 'http://192.168.0.223:81/bitcoin-php/examples/bip70.fetch.php?time=' . $time;
// Create a signer for x509+sha256 - this requires a readable private key and certificate chain.
// $signer = new PaymentRequestSigner('none');
$signer = new PaymentRequestSigner('x509+sha256', '/var/www/git/paymentrequestold/.keys/ssl.key', '/var/www/git/paymentrequestold/.keys/ssl.pem');
$builder = new PaymentRequestBuilder($signer, 'main', time());
// PaymentRequests contain outputs that the wallet will fulfill
$address = AddressFactory::fromString($destination);
$builder->addAddressPayment($address, $amount);
// Create the request, send it + headers
$request = $builder->send();
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Key\PrivateKeyFactory;
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Transaction\Transaction;
use BitWasp\Bitcoin\Transaction\TransactionInput;
use BitWasp\Bitcoin\Transaction\TransactionOutput;
use BitWasp\Bitcoin\Transaction\TransactionBuilder;
use BitWasp\Bitcoin\Transaction\TransactionFactory;
$ecAdapter = Bitcoin::getEcAdapter();
// Two users independently create private keys.
$pk1 = PrivateKeyFactory::fromHex('421c76d77563afa1914846b010bd164f395bd34c2102e5e99e0cb9cf173c1d87');
$pk2 = PrivateKeyFactory::fromHex('f7225388c1d69d57e6251c9fda50cbbf9e05131e5adb81e5aa0422402f048162');
// They exchange public keys, and a multisignature address is made (sorted keys)
$redeemScript = ScriptFactory::multisig(2, [$pk1->getPublicKey(), $pk2->getPublicKey()], true);
$outputScript = $redeemScript->getOutputScript();
// The address is funded with a transaction (fake, for the purposes of this script).
// You would do getrawtransaction normally
$spendTx = new Transaction();
$spendTx->getInputs()->addInput(new TransactionInput(
'4141414141414141414141414141414141414141414141414141414141414141',
0
));
$spendTx->getOutputs()->addOutput(new TransactionOutput(
50,
$outputScript
));
// One party wants to spend funds. He creates a transaction spending the funding tx to his address.
$builder = new TransactionBuilder($ecAdapter);
$builder->spendOutput($spendTx, 0)
->payToAddress($pk1->getAddress(), 50)
->signInputWithKey($pk1, $outputScript, 0, $redeemScript)
->signInputWithKey($pk2, $outputScript, 0, $redeemScript);
$rawTx = $builder->getTransaction()->getHex();
echo "Fully signed transaction: " . $builder->getTransaction()->getHex() . "\n";
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\MessageSigner\MessageSigner;
use BitWasp\Bitcoin\Key\PrivateKeyFactory;
$ec = Bitcoin::getEcAdapter();
$privateKey = PrivateKeyFactory::create(true);
$message = 'hi';
$signer = new MessageSigner($ec);
$signed = $signer->sign($message, $privateKey);
echo sprintf("Signed by %s\n%s\n", $privateKey->getAddress()->getAddress(), $signed->getBuffer()->getBinary());
if ($signer->verify($signed, $privateKey->getAddress())) {
echo "Signature verified!\n";
} else {
echo "Failed to verify signature!\n";
}
use BitWasp\Bitcoin\Crypto\Random\Random;
use BitWasp\Bitcoin\Mnemonic\MnemonicFactory;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
// Generate a mnemonic
$random = new Random();
$entropy = $random->bytes(64);
$bip39 = MnemonicFactory::bip39();
$seedGenerator = new Bip39SeedGenerator($bip39);
$mnemonic = $bip39->entropyToMnemonic($entropy);
// Derive a seed from mnemonic/password
$seed = $seedGenerator->getSeed($mnemonic, 'password');
echo $seed->getHex() . "\n";
$bip32 = \BitWasp\Bitcoin\Key\HierarchicalKeyFactory::fromEntropy($seed);
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Script\Interpreter\Native\Interpreter;
use BitWasp\Bitcoin\Script\Interpreter\Flags;
use BitWasp\Bitcoin\Transaction\Transaction;
$ec = \BitWasp\Bitcoin\Bitcoin::getEcAdapter();
$script = ScriptFactory::create()->op('OP_1')->op('OP_1')->op('OP_ADD');
echo "Formed script: " . $script . "\n";
print_r($script->getScriptParser()->parse());
$i = new Interpreter($ec, new Transaction(), new Flags(0));
$i->setScript($script)->run();
print_r($i->getStackState());