/**
  * create a new wallet
  *   - will generate a new primary seed (with password) and backup seed (without password)
  *   - send the primary seed (BIP39 'encrypted') and backup public key to the server
  *   - receive the blocktrail co-signing public key from the server
  *
  * Either takes one argument:
  * @param array $options
  *
  * Or takes three arguments (old, deprecated syntax):
  * (@nonPHP-doc) @param      $identifier
  * (@nonPHP-doc) @param      $password
  * (@nonPHP-doc) @param int  $keyIndex         override for the blocktrail cosigning key to use
  *
  * @return array[WalletInterface, (string)primaryMnemonic, (string)backupMnemonic]
  * @throws \Exception
  */
 public function createNewWallet($options)
 {
     if (!is_array($options)) {
         $args = func_get_args();
         $options = ["identifier" => $args[0], "password" => $args[1], "key_index" => isset($args[2]) ? $args[2] : null];
     }
     $identifier = $options['identifier'];
     $password = isset($options['passphrase']) ? $options['passphrase'] : (isset($options['password']) ? $options['password'] : null);
     $keyIndex = isset($options['key_index']) ? $options['key_index'] : 0;
     $walletPath = WalletPath::create($keyIndex);
     $storePrimaryMnemonic = isset($options['store_primary_mnemonic']) ? $options['store_primary_mnemonic'] : null;
     if (isset($options['primary_mnemonic']) && $options['primary_private_key']) {
         throw new \InvalidArgumentException("Can't specify Primary Mnemonic and Primary PrivateKey");
     }
     $primaryMnemonic = null;
     $primaryPrivateKey = null;
     if (!isset($options['primary_mnemonic']) && !isset($options['primary_private_key'])) {
         if (!$password) {
             throw new \InvalidArgumentException("Can't generate Primary Mnemonic without a passphrase");
         } else {
             // create new primary seed
             list($primaryMnemonic, $primarySeed, $primaryPrivateKey) = $this->newPrimarySeed($password);
             if ($storePrimaryMnemonic !== false) {
                 $storePrimaryMnemonic = true;
             }
         }
     } else {
         if (isset($options['primary_mnemonic'])) {
             $primaryMnemonic = $options['primary_mnemonic'];
         } else {
             if (isset($options['primary_private_key'])) {
                 $primaryPrivateKey = $options['primary_private_key'];
             }
         }
     }
     if ($storePrimaryMnemonic && $primaryMnemonic && !$password) {
         throw new \InvalidArgumentException("Can't store Primary Mnemonic on server without a passphrase");
     }
     if ($primaryPrivateKey) {
         if (is_string($primaryPrivateKey)) {
             $primaryPrivateKey = [$primaryPrivateKey, "m"];
         }
     } else {
         $primaryPrivateKey = BIP32::master_key(BIP39::mnemonicToSeedHex($primaryMnemonic, $password), 'bitcoin', $this->testnet);
     }
     if (!$storePrimaryMnemonic) {
         $primaryMnemonic = false;
     }
     // create primary public key from the created private key
     $primaryPublicKey = BIP32::build_key($primaryPrivateKey, (string) $walletPath->keyIndexPath()->publicPath());
     if (isset($options['backup_mnemonic']) && $options['backup_public_key']) {
         throw new \InvalidArgumentException("Can't specify Backup Mnemonic and Backup PublicKey");
     }
     $backupMnemonic = null;
     $backupPublicKey = null;
     if (!isset($options['backup_mnemonic']) && !isset($options['backup_public_key'])) {
         list($backupMnemonic, $backupSeed, $backupPrivateKey) = $this->newBackupSeed();
     } else {
         if (isset($options['backup_mnemonic'])) {
             $backupMnemonic = $options['backup_mnemonic'];
         } else {
             if (isset($options['backup_public_key'])) {
                 $backupPublicKey = $options['backup_public_key'];
             }
         }
     }
     if ($backupPublicKey) {
         if (is_string($backupPublicKey)) {
             $backupPublicKey = [$backupPublicKey, "m"];
         }
     } else {
         $backupPublicKey = BIP32::extended_private_to_public(BIP32::master_key(BIP39::mnemonicToSeedHex($backupMnemonic, ""), 'bitcoin', $this->testnet));
     }
     // create a checksum of our private key which we'll later use to verify we used the right password
     $checksum = BIP32::key_to_address($primaryPrivateKey[0]);
     // send the public keys to the server to store them
     //  and the mnemonic, which is safe because it's useless without the password
     $data = $this->_createNewWallet($identifier, $primaryPublicKey, $backupPublicKey, $primaryMnemonic, $checksum, $keyIndex);
     // received the blocktrail public keys
     $blocktrailPublicKeys = $data['blocktrail_public_keys'];
     $wallet = new Wallet($this, $identifier, $primaryMnemonic, [$keyIndex => $primaryPublicKey], $backupPublicKey, $blocktrailPublicKeys, $keyIndex, $this->network, $this->testnet, $checksum);
     $wallet->unlock($options);
     // return wallet and backup mnemonic
     return [$wallet, $primaryMnemonic, $backupMnemonic, $blocktrailPublicKeys];
 }
require_once __DIR__ . '/../vendor/autoload.php';
// Fixed seed and derivation to test with
$seed = '41414141414141414141414141414141414141';
$def = "0'/0";
// Create master key from seed
$master = BIP32::master_key($seed);
echo "\nMaster key\n m           : {$master[0]} \n";
// Create derived key from master key + derivation
$key = BIP32::build_key($master, $def);
// Display private extended key and the address that's derived from it.
echo "Generated key: note that all depth=1 keys are hardened. \n {$key[1]}        : {$key[0]}\n";
echo "             : " . BIP32::key_to_address($key[0]) . "\n";
// Convert the extended private key to the public key, and display the address that's derived from it.
$pub = BIP32::extended_private_to_public($key);
echo "Public key\n {$pub[1]}        : {$pub[0]}\n";
echo "             : " . BIP32::key_to_address($pub[0]) . "\n";
/////////////////////////////
// We're gonna spent the first txout from this tx:
//  https://www.blocktrail.com/BTC/tx/4a2231e13182cdb64fa2f9aae38fca46549891e9dc15e8aaf484d82fc6e0a1d8
// Set up inputs here
$inputs = array(array('txid' => '4a2231e13182cdb64fa2f9aae38fca46549891e9dc15e8aaf484d82fc6e0a1d8', 'vout' => 0));
// Set up outputs here
$outputs = array('1KuE17Fbcdsn3Ns5T9Wzi1epurRnKC9qVr' => BitcoinLib::toSatoshi(0.0004));
////////////////////////////
// Parameters for signing.
// Create JSON inputs parameter
// - These can come from bitcoind, or just knowledge of the txid/vout/scriptPubKey,
//   and redeemScript if needed.
$json_inputs = json_encode(array(array('txid' => '4a2231e13182cdb64fa2f9aae38fca46549891e9dc15e8aaf484d82fc6e0a1d8', 'vout' => 0, 'scriptPubKey' => '76a914' . 'bf012bde5bd12eb7f9a66de5697b241b65a9a3c9' . '88ac')));
// build wallet from private key(s)
$wallet = array();
Esempio n. 3
0
 protected function _createTestWallet(BlocktrailSDKInterface $client, $identifier, $passphrase, $primaryMnemonic, $backupMnemonic, $readOnly = false)
 {
     $walletPath = WalletPath::create(9999);
     $seed = BIP39::mnemonicToSeedHex($primaryMnemonic, $passphrase);
     $primaryPrivateKey = BIP32::master_key($seed, 'bitcoin', true);
     $primaryPublicKey = BIP32::build_key($primaryPrivateKey, (string) $walletPath->keyIndexPath()->publicPath());
     $seed = BIP39::mnemonicToSeedHex($backupMnemonic, "");
     $backupPrivateKey = BIP32::master_key($seed, 'bitcoin', true);
     $backupPublicKey = BIP32::build_key($backupPrivateKey, (string) "M");
     $testnet = true;
     $checksum = BIP32::key_to_address($primaryPrivateKey[0]);
     $result = $client->_createNewWallet($identifier, $primaryPublicKey, $backupPublicKey, $primaryMnemonic, $checksum, 9999);
     $blocktrailPublicKeys = $result['blocktrail_public_keys'];
     $keyIndex = $result['key_index'];
     $wallet = new Wallet($client, $identifier, $primaryMnemonic, [$keyIndex => $primaryPublicKey], $backupPublicKey, $blocktrailPublicKeys, $keyIndex, 'bitcoin', $testnet, $checksum);
     if (!$readOnly) {
         $wallet->unlock(['password' => $passphrase]);
     }
     return $wallet;
 }
Esempio n. 4
0
 /**
  * unlock wallet so it can be used for payments
  *
  * @param          $options ['primary_private_key' => key] OR ['passphrase' => pass]
  * @param callable $fn
  * @return bool
  * @throws \Exception
  */
 public function unlock($options, callable $fn = null)
 {
     // explode the wallet data
     $password = isset($options['passphrase']) ? $options['passphrase'] : (isset($options['password']) ? $options['password'] : null);
     $primaryMnemonic = $this->primaryMnemonic;
     $primaryPrivateKey = isset($options['primary_private_key']) ? $options['primary_private_key'] : null;
     if ($primaryMnemonic && $primaryPrivateKey) {
         throw new \InvalidArgumentException("Can't specify Primary Mnemonic and Primary PrivateKey");
     }
     if (!$primaryMnemonic && !$primaryPrivateKey) {
         throw new \InvalidArgumentException("Can't init wallet with Primary Mnemonic or Primary PrivateKey");
     }
     if ($primaryMnemonic && !$password) {
         throw new \InvalidArgumentException("Can't init wallet with Primary Mnemonic without a passphrase");
     }
     if ($primaryPrivateKey) {
         if (is_string($primaryPrivateKey)) {
             $primaryPrivateKey = [$primaryPrivateKey, "m"];
         }
     } else {
         // convert the mnemonic to a seed using BIP39 standard
         $primarySeed = BIP39::mnemonicToSeedHex($primaryMnemonic, $password);
         // create BIP32 private key from the seed
         $primaryPrivateKey = BIP32::master_key($primarySeed, $this->network, $this->testnet);
     }
     $this->primaryPrivateKey = BIP32Key::create($primaryPrivateKey);
     // create checksum (address) of the primary privatekey to compare to the stored checksum
     $checksum = BIP32::key_to_address($primaryPrivateKey[0]);
     if ($checksum != $this->checksum) {
         throw new \Exception("Checksum [{$checksum}] does not match [{$this->checksum}], most likely due to incorrect password");
     }
     $this->locked = false;
     // if the response suggests we should upgrade to a different blocktrail cosigning key then we should
     if (isset($data['upgrade_key_index'])) {
         $this->upgradeKeyIndex($data['upgrade_key_index']);
     }
     if ($fn) {
         $fn($this);
         $this->lock();
     }
 }