/** * @param string $hexPrivateKey * @param bool $compressed * @return PrivateKeyInterface * @throws BlockCypherInvalidPrivateKeyException */ public static function importPrivateKeyFromHex($hexPrivateKey, $compressed = true) { $privateKey = null; try { $privateKey = PrivateKeyFactory::fromHex($hexPrivateKey, $compressed); } catch (\Exception $e) { throw new BlockCypherInvalidPrivateKeyException('Invalid private key format, hex expected.' . $e->getMessage()); } return $privateKey; }
/** * @param Parser $parser * @return HierarchicalKey * @throws ParserOutOfRange */ public function fromParser(Parser &$parser) { try { list($bytes, $depth, $parentFingerprint, $sequence, $chainCode, $keyData) = $this->getTemplate()->parse($parser); $bytes = $bytes->getHex(); } catch (ParserOutOfRange $e) { throw new ParserOutOfRange('Failed to extract HierarchicalKey from parser'); } if ($bytes !== $this->network->getHDPubByte() && $bytes !== $this->network->getHDPrivByte()) { throw new \InvalidArgumentException("HD key magic bytes do not match network magic bytes"); } $key = $this->network->getHDPrivByte() == $bytes ? PrivateKeyFactory::fromHex($keyData->slice(1)->getHex(), true, $this->ecAdapter) : PublicKeyFactory::fromHex($keyData->getHex(), $this->ecAdapter); return new HierarchicalKey($this->ecAdapter, $depth, $parentFingerprint, $sequence, $chainCode, $key); }
/** * @param string $privateKey * @throws \Exception */ private function checkHexPrivateKey($privateKey) { if (!is_string($privateKey)) { throw new \Exception("Invalid private key format. String expected."); } try { PrivateKeyFactory::fromHex($privateKey); } catch (\Exception $e) { throw new \Exception("Invalid private key format. Hex format expected."); } }
/** * @param Buffer $entropy * @param EcAdapterInterface $ecAdapter * @return HierarchicalKey */ public static function fromEntropy(Buffer $entropy, EcAdapterInterface $ecAdapter = null) { $ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter(); $hash = Hash::hmac('sha512', $entropy, new Buffer('Bitcoin seed', null, $ecAdapter->getMath())); return new HierarchicalKey($ecAdapter, 0, 0, 0, $hash->slice(32, 32)->getInt(), PrivateKeyFactory::fromHex($hash->slice(0, 32)->getHex(), true, $ecAdapter)); }
use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Key\PublicKeyFactory; use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\Rpc\RpcFactory; $network = Bitcoin::getNetwork(); $host = '127.0.0.1'; $port = '18332'; $user = getenv('BITCOINLIB_RPC_USER') ?: 'bitcoinrpc'; $pass = getenv('BITCOINLIB_RPC_PASSWORD') ?: 'BBpsLqmCCx7Vp8sRd5ygDxFkHZBgWLTTi55QwWgN6Ng6'; Bitcoin::setNetwork(\BitWasp\Bitcoin\Network\NetworkFactory::bitcoinTestnet()); $network = Bitcoin::getNetwork(); $ecAdapter = Bitcoin::getEcAdapter(); $bitcoind = RpcFactory::bitcoind($host, $port, $user, $pass); $privateKey1 = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d5', true); $privateKey2 = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d6', true); $redeemScript = ScriptFactory::multisig(2, array($privateKey1->getPublicKey(), $privateKey2->getPublicKey())); $multisig = $redeemScript->getAddress(); echo "[P2SH address: " . $multisig->getAddress($network) . " ]\n"; echo "[private key order: " . implode(", ", array_map(function (PublicKeyInterface $publicKey) use($privateKey1, $privateKey2) { if ($publicKey->getBinary() == $privateKey1->getPublicKey()->getBinary()) { return "1"; } else { return "2"; } }, $redeemScript->getKeys())) . "]\n"; $myTx = $bitcoind->getrawtransaction('6d4f5d2cce43660c29e03a794497da3f204312358ca6a6e47035ef916ce19db9', true); $spendOutput = 0; $recipient = AddressFactory::fromString('n1b2a9rFvuU9wBgBaoWngNvvMxRV94ke3x'); echo "[Send to: " . $recipient->getAddress($network) . " \n"; // Prep work - importing from a tx will only bring container to contents of $new - no metadata
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Transaction\Factory\TxSigner; use BitWasp\Bitcoin\Transaction\Factory\TxBuilder; $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. $redeemScript = ScriptFactory::scriptPubKey()->multisig(2, [$pk1->getPublicKey(), $pk2->getPublicKey()]); $os = ScriptFactory::scriptPubKey()->payToScriptHash($redeemScript); // The address is funded with a transaction (fake, for the purposes of this script). // You would do getrawtransaction normall $fundTx = (new TxBuilder())->input('4141414141414141414141414141414141414141414141414141414141414141', 0)->output(50, $os)->get(); // One party wants to spend funds. He creates a transaction spending the funding tx to his address. $spendTx = (new TxBuilder())->spendOutputFrom($fundTx, 0)->payToAddress(50, $pk1->getAddress())->get(); // Two parties sign the transaction (can be done in steps) $signer = new TxSigner($ecAdapter, $spendTx); $signer->sign(0, $pk1, $os, $redeemScript)->sign(0, $pk2, $os, $redeemScript); $rawTx = $signer->get()->getHex(); echo "Fully signed transaction: " . $signer->get()->getHex() . "\n";
/** * @param PrivateKeyInterface $oldPrivate * @param string $newBinary * @return \BitWasp\Bitcoin\Key\PrivateKey */ private function getRelatedPrivateKey(PrivateKeyInterface $oldPrivate, $newBinary) { return PrivateKeyFactory::fromHex(bin2hex($newBinary), $oldPrivate->isCompressed(), $this); }
// https://github.com/Bit-Wasp/bitcoin-php // Run on console: // php -f .\sample\transaction-api\CreateTransactionWithThirdPartySoftware.php use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Transaction\TransactionBuilder; use BitWasp\Bitcoin\Transaction\TransactionFactory; require __DIR__ . '/../bootstrap.php'; $debug = false; Bitcoin::setNetwork(\BitWasp\Bitcoin\Network\NetworkFactory::bitcoinTestnet()); $network = Bitcoin::getNetwork(); $ecAdapter = Bitcoin::getEcAdapter(); // Import private key $compressed = true; $privateKey = PrivateKeyFactory::fromHex('1551558c3b75f46b71ec068f9e341bf35ee6df361f7b805deb487d8a4d5f055e', $compressed); if ($debug) { echo "[Key: " . $privateKey->toWif($network) . "]\n"; echo "[Address " . $privateKey->getAddress()->getAddress($network) . "]\n"; } // In order to run the sample you will need: // 1.- Use the faucet to fund source address // Faucet https://accounts.blockcypher.com/testnet-faucet?a=n3D2YXwvpoPg8FhcWpzJiS3SvKKGD8AXZ4 // 2.- Get unspent transaction outputs (UTXOs) and select one: // https://api.blockcypher.com/v1/btc/test3/addrs/n3D2YXwvpoPg8FhcWpzJiS3SvKKGD8AXZ4?unspentOnly=true // 3.- Get the hex tx for the selected UTXO: // https://live.blockcypher.com/btc-testnet/tx/e7f034f4a56999d04d8a3a8f07dca10e87cd4a7fd2a779e9ecd41c57afec84f8/ // 4.- Copy Tx Hex and paste here: $txHex = '0100000001b674eafd9c1a79402661e7e7b37746145869260c29263f213f6f120ea8a95574010000006b483045022100ac406c14ef2da774d64d5504340fd278a827a99941cf0bef26fdff17c191ffa4022016a69a281ec1fcdf22c34543ff97a5c332ed12856fb44e525cf8ba3aea7c2d4101210274cb62e999bdf96c9b4ef8a2b44c1ac54d9de879e2ee666fdbbf0e1a03090cdfffffffff02e8030000000000001976a914a93806b8ae200fffca565f7cf9ef3ab17d4ffe8888ac204e0000000000001976a914edeed3ce7f485e44bc33969af08ec9250510f83f88ac00000000'; $myTx = TransactionFactory::fromHex($txHex); $spendOutput = 0;
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Transaction\TransactionFactory; $ecAdapter = Bitcoin::getEcAdapter(); $math = $ecAdapter->getMath(); $privHex1 = '421c76d77563afa1914846b010bd164f395bd34c2102e5e99e0cb9cf173c1d87'; $privHex2 = 'f7225388c1d69d57e6251c9fda50cbbf9e05131e5adb81e5aa0422402f048162'; $redeemScriptHex = '52410443f3ce7c4ddf438900a6662420511ea48321f8cedd3e63943700b07ac9752a6bf18230095730b18f2d3c3dbdc0a892ca62b1722730f183d370963d6f4d3e20c84104f260c8b554e9d0921c507fb231d0e226ba17462078825c56170facb6567dcec700750bd529f4361da21f59fbfc7d0bce319fdef4e7c524e82d3e313e92b1b34752ae'; $txid = '4141414141414141414141414141414141414141414141414141414141414141'; $vout = 0; $amount = '161662670'; $fee = '12345'; $amountAfterFee = $math->sub($amount, $fee); // Two users independently create private keys. $pk1 = \BitWasp\Bitcoin\Key\PrivateKeyFactory::fromHex($privHex1); $pk2 = \BitWasp\Bitcoin\Key\PrivateKeyFactory::fromHex($privHex2); $outpoint = new \BitWasp\Bitcoin\Transaction\OutPoint(\BitWasp\Buffertools\Buffer::hex($txid), $vout); $redeemScript = new \BitWasp\Bitcoin\Script\P2shScript(\BitWasp\Bitcoin\Script\ScriptFactory::fromHex($redeemScriptHex)); $os = $redeemScript->getOutputScript(); // One party (pk1) wants to spend funds. He creates a transaction spending the funding tx to his address. $spendTx = TransactionFactory::build()->spendOutPoint($outpoint)->payToAddress($amountAfterFee, $pk1->getAddress())->get(); // Two parties sign the transaction (can be done in steps) $signer = TransactionFactory::sign($spendTx); $signer->sign(0, $pk1, $os, $redeemScript)->sign(0, $pk2, $os, $redeemScript); $signed = $signer->get(); $fundTx = TransactionFactory::build()->input('4d7adb19fff03892a11924f2a9188e36dbbdf0f3bb341b6514475e4df238184b', 0)->output(1000000, $os)->get(); echo $fundTx->getHex() . "\n"; echo $fundTx->getTxId()->getHex() . "\n"; echo "Fully signed transaction: " . $signed->getHex() . "\n";
<?php require "../vendor/autoload.php"; use BitWasp\Buffertools\Buffer; use BitWasp\Bitcoin\Crypto\Hash; use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Transaction\TransactionFactory; use BitWasp\Bitcoin\Script\ScriptFactory; $ent = Hash::sha256(new Buffer('abc')); $priv = PrivateKeyFactory::fromHex($ent); $publicKey = $priv->getPublicKey(); $outputScript = ScriptFactory::scriptPubKey()->payToPubKeyHash($publicKey); $tx = TransactionFactory::build()->input('10001234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234', 0)->payToAddress(50, $publicKey->getAddress())->get(); $signed = TransactionFactory::sign($tx)->sign(0, $priv, $outputScript)->get(); echo $signed->getHex(); $consensus = ScriptFactory::consensus(); $validator = $signed->validator(); var_dump($validator->checkSignatures($consensus, [$outputScript]));