Skip to content

Commit

Permalink
feat: php8 support
Browse files Browse the repository at this point in the history
These changes enable hd-wallet-derive to be used with php8+

NOT tested with previous PHP versions, and will probably not work.

composer:
 + add dep on gmp extension
 + bump php dep to 8+
 + change bitwasp/bitcoin dep to protonlabs/bitcoin, as they are
   the new maintainers and have php8 fixes.

Utils/FlexNetwork.php:
 + fix a couple of type cast errors.

WalletDerive.php:
 + add derive_path() method to support both absolute and relative
   bip32 paths.
 + fix a couple of type access errors.

eth.test.php
 + ignore missing array keys
  • Loading branch information
dan-da committed Nov 5, 2023
1 parent 91e1a87 commit 5732189
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"name": "dan-da/hd-wallet-derive",
"minimum-stability": "dev",
"require": {
"bitwasp/bitcoin": "dev-master#8782bc6c470e342d4e0cb67eb036974f133b950b",
"ext-json": "*",
"php": ">=5.5",
"ext-gmp": "*",
"php": ">=8",
"dan-da/texttable-php": "1.0.3",
"dan-da/strictmode-php": "1.0.1",
"dan-da/strictmode-php": "^1.0.2",
"dan-da/coinparams": "0.2.9",
"olegabr/keccak": "1.0.4"
"olegabr/keccak": "1.0.4",
"protonlabs/bitcoin": "dev-main"
},

"require-dev": {
Expand Down
6 changes: 3 additions & 3 deletions src/Utils/FlexNetwork.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function __construct($coin) {
// could be made configurable.
$scripthash = @$prefixes['scripthash2'] ?
$prefixes['scripthash2'] : $prefixes['scripthash'];

$this->base58PrefixMap = [
self::BASE58_ADDRESS_P2PKH => self::dh(@$params['prefixes']['public']),
self::BASE58_ADDRESS_P2SH => self::dh($scripthash),
Expand Down Expand Up @@ -66,13 +66,13 @@ function __construct($coin) {
* and prepends 0 if necessary to make length an even number.
*/
static private function th($hex, $prepend_zero = false) {
$hex = substr($hex, 2);
$hex = @substr($hex, 2);
$pre = strlen($hex) % 2 == 0 ? '' : '0';
return $pre . $hex;
}

static private function dh($dec, $prepend_zero = false) {
$hex = dechex($dec);
$hex = dechex((int)$dec);
$pre = strlen($hex) % 2 == 0 ? '' : '0';
return $pre . $hex;
}
Expand Down
44 changes: 40 additions & 4 deletions src/WalletDerive.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
// For HD-Wallet Key Derivation
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory;
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKey;
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKeySequence;
use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress;
use BitWasp\Bitcoin\Crypto\Random\Random;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
use BitWasp\Bitcoin\Mnemonic\MnemonicFactory;
use Exception;
use BitWasp\Bitcoin\Exceptions\InvalidDerivationException;
use App\Utils\NetworkCoinFactory;
use App\Utils\MyLogger;
use App\Utils\CashAddress;
Expand Down Expand Up @@ -135,8 +138,9 @@ private function derive_keys_worker($params, $key)
for($i = $start; $i < $end; $i++)
{
$path = sprintf($path_mask, $i);
$key = $master->derivePath($path);


// $key = $master->derivePath($path);
$key = $this->derive_path($master, $path);
$this->derive_key_worker($coin, $symbol, $network, $addrs, $key, $key_type, $i, $path);

$count = $i + 1;
Expand All @@ -151,6 +155,32 @@ private function derive_keys_worker($params, $key)

return $addrs;
}

// This function is a replacement for HierarchicalKey::derivePath()
// since that function now accepts only relative paths.
//
// This function is exactly the same except it will detect if first
// char is 'm' or 'M' and then will call decodeAbsolute() instead.
private function derive_path($key, string $path): HierarchicalKey {
$sequences = new HierarchicalKeySequence();
$is_abs = in_array(@$path[0], ['m', 'M']);
$parts = $is_abs ? @$sequences->decodeAbsolute($path)[1] : $sequences->decodeRelative($path);
$numParts = count($parts);

for ($i = 0; $i < $numParts; $i++) {
try {
$key = $key->deriveChild($parts[$i]);
} catch (InvalidDerivationException $e) {
if ($i === $numParts - 1) {
throw new InvalidDerivationException($e->getMessage());
} else {
throw new InvalidDerivationException("Invalid derivation for non-terminal index: cannot use this path!");
}
}
}

return $key;
}

private function derive_key_worker($coin, $symbol, $network, &$addrs, $key, $key_type, $index, $path) {

Expand Down Expand Up @@ -214,6 +244,9 @@ private function getKeyTypeFromCoinAndKey($coin, $key) {

$ext = $this->getExtendedPrefixes($coin);
foreach($ext as $kt => $info) {
if(!is_array($info)) {
continue;
}
if( $key_prefix == strtolower(@$info['public']) ) {
return $kt[0];
}
Expand All @@ -234,7 +267,6 @@ private function getSerializer($coin, $network, $key_type) {

$prefix = $this->getScriptPrefixForKeyType($coin, $key_type);
$config = new GlobalPrefixConfig([new NetworkConfig($network, [$prefix]),]);
//print_r($config); exit;

$serializer = new Base58ExtendedKeySerializer(new ExtendedKeySerializer($adapter, $config));
return $serializer;
Expand Down Expand Up @@ -278,6 +310,9 @@ private function getExtendedPrefixes($coin) {
$val = $val ?: [];
// ensure no entries with empty values.
foreach($val as $k => $v) {
if(!is_array($v)) {
continue;
}
if(!@$v['public'] || !@$v['private']) {
unset($val[$k]);
}
Expand Down Expand Up @@ -464,7 +499,8 @@ protected function genKeysFromSeed($coin, $seedinfo) {
$bip32path = $this->getCoinBip44ExtKeyPathPurpose($coin, $purpose);
if($bip32path) {
// derive extended priv/pub keys.
$prv = $xkey->derivePath($bip32path);
// $prv = $xkey->derivePath($bip32path);
$prv = $this->derive_path($xkey, $bip32path);
$pub = $prv->withoutPrivateKey();
$row[$pf . 'path'] = $bip32path;
$row['xprv'] = $this->toExtendedKey($coin, $prv, $network, $key_type);
Expand Down
4 changes: 2 additions & 2 deletions tests/eth.test.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ protected function test_eth_addr() {
'format' => 'json',
];
$r = $this->derive_params( $params );
$this->eq( $r['address'], $addr_correct, 'address' );
$this->eq( $r['privkey'], $privkey_correct, 'privkey' );
$this->eq( @$r['address'], $addr_correct, 'address' );
$this->eq( @$r['privkey'], $privkey_correct, 'privkey' );
}

}

0 comments on commit 5732189

Please sign in to comment.