/**
  * 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];
 }
Esempio n. 2
0
 public function testNewBlankWithoutMnemonicsWallet()
 {
     $client = $this->setupBlocktrailSDK();
     $identifier = $this->getRandomTestIdentifier();
     $primaryPrivateKey = BIP32::master_key(BIP39::mnemonicToSeedHex(BIP39::entropyToMnemonic(BIP39::generateEntropy(512)), "password"), 'bitcoin', true);
     $backupPublicKey = BIP32::extended_private_to_public(BIP32::master_key(BIP39::mnemonicToSeedHex(BIP39::entropyToMnemonic(BIP39::generateEntropy(512)), "password"), 'bitcoin', true));
     /**
      * @var $wallet \Blocktrail\SDK\Wallet
      */
     $e = null;
     try {
         $wallet = $client->initWallet(["identifier" => $identifier]);
     } catch (ObjectNotFound $e) {
         list($wallet, $primaryMnemonic, $backupMnemonic, $blocktrailPublicKeys) = $client->createNewWallet(["identifier" => $identifier, "primary_private_key" => $primaryPrivateKey, "backup_public_key" => $backupPublicKey, "key_index" => 9999]);
     }
     $this->assertTrue(!!$e, "New wallet with ID [{$identifier}] already exists...");
     $wallet = $client->initWallet(["identifier" => $identifier, "primary_private_key" => $primaryPrivateKey]);
     $this->wallets[] = $wallet;
     // store for cleanup
     $this->assertEquals(0, $wallet->getBalance()[0]);
     $e = null;
     try {
         $wallet->pay(["2N6Fg6T74Fcv1JQ8FkPJMs8mYmbm9kitTxy" => BlocktrailSDK::toSatoshi(0.001)]);
     } catch (\Exception $e) {
     }
     $this->assertTrue(!!$e, "Wallet without balance is able to pay...");
 }
use BitWasp\BitcoinLib\BitcoinLib;
use BitWasp\BitcoinLib\RawTransaction;
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')));
 public function testChildKeyDerivationOne()
 {
     $test_vectors = [0 => ['master' => '000102030405060708090a0b0c0d0e0f', 'ckd' => [0 => ['child' => "0'", 'priv' => 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7', 'pub' => 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw'], 1 => ['child' => '1', 'priv' => 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs', 'pub' => 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'], 2 => ['child' => "2'", 'priv' => 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM', 'pub' => 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'], 3 => ['child' => '2', 'priv' => 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334', 'pub' => 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV'], 4 => ['child' => '1000000000', 'priv' => 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76', 'pub' => 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy']]], 1 => ['master' => 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542', 'ckd' => [0 => ['child' => "0", 'priv' => 'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt', 'pub' => 'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH'], 1 => ['child' => "2147483647'", 'priv' => 'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9', 'pub' => 'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a'], 2 => ['child' => "1", 'priv' => 'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef', 'pub' => 'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon'], 3 => ['child' => "2147483646'", 'priv' => 'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc', 'pub' => 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL'], 4 => ['child' => '2', 'priv' => 'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j', 'pub' => 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt']]]];
     foreach ($test_vectors as $test => $vector) {
         $master = BIP32::master_key($vector['master']);
         $key = $master;
         foreach ($vector['ckd'] as $test_array) {
             $key = BIP32::build_key($key, $test_array['child']);
             $this->assertEquals($key[0], $test_array['priv']);
             $pub = BIP32::extended_private_to_public($key);
             $this->assertEquals($pub[0], $test_array['pub']);
         }
     }
 }
Esempio n. 5
0
 /**
  * upgrade wallet to different blocktrail cosign key
  *
  * @param $keyIndex
  * @return bool
  * @throws \Exception
  */
 public function upgradeKeyIndex($keyIndex)
 {
     if ($this->locked) {
         throw new \Exception("Wallet needs to be unlocked to upgrade key index");
     }
     $walletPath = WalletPath::create($keyIndex);
     // do the upgrade to the new 'key_index'
     $primaryPublicKey = BIP32::extended_private_to_public(BIP32::build_key($this->primaryPrivateKey->tuple(), (string) $walletPath->keyIndexPath()));
     $result = $this->sdk->upgradeKeyIndex($this->identifier, $keyIndex, $primaryPublicKey);
     $this->primaryPublicKeys[$keyIndex] = BIP32Key::create($primaryPublicKey);
     $this->keyIndex = $keyIndex;
     $this->walletPath = $walletPath;
     // update the blocktrail public keys
     foreach ($result['blocktrail_public_keys'] as $keyIndex => $pubKey) {
         if (!isset($this->blocktrailPublicKeys[$keyIndex])) {
             $this->blocktrailPublicKeys[$keyIndex] = BIP32Key::create($pubKey);
         }
     }
     return true;
 }
$wallet[0] = BIP32::master_key('b861e093a58718e145b9791af35fb111');
$wallet[1] = BIP32::master_key('b861e093a58718e145b9791af35fb222');
$wallet[2] = BIP32::master_key('b861e093a58718e145b9791af35fb333');
print_r($wallet);
echo "Now we will generate a m/0' extended key. These will yield a private key\n";
$user[0] = BIP32::build_key($wallet[0][0], "3'");
$user[1] = BIP32::build_key($wallet[1][0], "23'");
$user[2] = BIP32::build_key($wallet[2][0], "9'");
print_r($user);
// As the previous is a private key, we should convert to the corresponding
// public key: M/0'
echo "As the previous is a private key, we should convert it to the corresponding\n";
echo "public key: M/0' \n";
$pub[0] = BIP32::extended_private_to_public($user[0]);
$pub[1] = BIP32::extended_private_to_public($user[1]);
$pub[2] = BIP32::extended_private_to_public($user[2]);
print_r($pub);
echo "This is the key you will ask your users for. For repeated transactions\n";
echo "BIP32 allows you to deterministically generate public keys, meaning less\n";
echo "effort for everyone involved\n\n";
echo "Now we can generate many multisignature addresses from what we have here: \n";
for ($i = 0; $i < 3; $i++) {
    $bip32key[0] = BIP32::build_key($pub[0], "0/{$i}");
    $bip32key[1] = BIP32::build_key($pub[1], "0/{$i}");
    $bip32key[2] = BIP32::build_key($pub[2], "0/{$i}");
    print_r($bip32key);
    $pubkey[0] = BIP32::extract_public_key($bip32key[0]);
    $pubkey[1] = BIP32::extract_public_key($bip32key[1]);
    $pubkey[2] = BIP32::extract_public_key($bip32key[2]);
    print_r($pubkey);
    print_r(RawTransaction::create_multisig(2, $pubkey));