| Notation | Description | 
|---|---|
| / | Indicate a new branch with number of new child. | 
| ' | Hardened Child means that no new child can be derived by extended public key, unless you derived from extended private key. Index range from 2147483648 to 4294967296. | 
| without ' | Normal Child is the inverse of Hardened Child. Index range from 0 to 2147483647. | 
<?php 
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Crypto\Random\Random;
use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39Mnemonic;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
use BitWasp\Bitcoin\Mnemonic\MnemonicFactory;
use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKey;
include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");
$result = 0;
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
	
	try {
		
		$hdFactory = new HierarchicalKeyFactory();
			
		$bip32Root = $hdFactory->fromExtended($_POST['extended_priv']);
		
		if ($_POST['relative_path']) {
			
			$key = $bip32Root->derivePath($_POST['relative_path']);
			
			$displayPubkey = $key->getPublicKey()->getHex();
			$displayPrikey = $key->getPrivateKey()->getHex();
			$displayExtendedPrikey = $key->toExtendedKey();
			$displayExtendedPubkey = $key->toExtendedPublicKey();
		}
		
		$result = 1;
	} catch (Exception $e) {
        $errmsg .= "Problem found. " . $e->getMessage();
    }
}
if ($errmsg) {
?>
	<div class="alert alert-danger">
		<strong>Error!</strong> <?php echo $errmsg?>
	</div>
<?php
}
if ($result) {
?>
	<h5>Derivation</h5>
	<div class="table-responsive">
		<table border=0 class='table'>
			<tr><td>Relative Path</td><td><?php echo $_POST['relative_path']?></td></tr>
			<tr><td>Public Key</td><td><?php echo $displayPubkey?></td></tr>
			<tr><td>Private Key</td><td><?php echo $displayPrikey?></td></tr>
			<tr><td>Bip32 Extended Private Key</td><td><?php echo $displayExtendedPrikey?></td></tr>
			<tr><td>Bip32 Extended Public Key</td><td><?php echo $displayExtendedPubkey?></td></tr>
		</table>
	</div>
<?php
}
?>
<form action='' method='post'>
	
	<div class="form-group">
		<label for="extended_priv">Bip32 Extended Private Key (Extend From):</label>
		
		<div class="input-group mb-3">
			<input class="form-control" type='text' name='extended_priv' id='extended_priv' value='<?php echo $_POST['extended_priv']?>'>
		</div>
	</div>
	
	<div class="form-group">
		<label for="relative_path">Relative Path (Extend To):</label>
		<input class="form-control" type='text' name='relative_path' id='relative_path' value='<?php echo htmlentities($_POST['relative_path'],ENT_QUOTES)?>'>
		* Do not start with /
	</div>
	
	<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php 
include_once("html_iframe_footer.php");		 		
	<?php 
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39Mnemonic;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
use BitWasp\Bitcoin\Mnemonic\MnemonicFactory;
use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Key\Deterministic\HierarchicalKey;
use BitWasp\Bitcoin\Network\NetworkFactory;
use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress;
use \BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Key\PublicKey;
use kornrunner\Keccak;
include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");
function toChecksumAddress($address) 
{
	
	$address = strtolower(str_replace('0x', '', $address));
	$hash = Keccak::hash(strtolower($address), 256);
	$checksumAddress = '0x';
	
	for($i=0;$i<strlen($address);$i++) {
		
		if (intval($hash{$i}, 16) > 7) {
			$checksumAddress .= strtoupper($address{$i});
		} else {
			$checksumAddress .= $address{$i};
		}
	}
	
	return $checksumAddress;
	
}
$details = [];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
	
	try {
		$networkClass = ($_POST['network'] == "ethereum" ? "bitcoin": $_POST['network']);
		
        Bitcoin::setNetwork(NetworkFactory::$networkClass());
        $network        = Bitcoin::getNetwork();
		$hdFactory = new HierarchicalKeyFactory();
		
		$key = $hdFactory->fromExtended($_POST['xpub'], $network);
		
		$indexes = range((int)$_POST['from_index'],(int)$_POST['to_index']);
		$ecAdapter = Bitcoin::getEcAdapter();
		
		foreach($indexes as $index) {
			$relativePath = strlen($_POST['relative_path']) >0 ? $_POST['relative_path'] . "/"  : "";
			
			$childKey = $key->derivePath( $relativePath . $index);
			
			$publicKey = $childKey->getPublicKey();
			//decompress public key
			$dePublicKey = new PublicKey($ecAdapter,$publicKey->getPoint(),false);
			
			if ($_POST['network'] == 'ethereum') {
				
				$madeUpEthAddress = substr($dePublicKey->getHex(), 2);
				
				$hash = Keccak::hash(hex2bin($madeUpEthAddress), 256);
				$ethAddress = toChecksumAddress('0x' . substr($hash, -40));
				$details[$relativePath . $index] = ["decompressed_pub"=>$dePublicKey->getHex(), "compressed_pub"=>$publicKey->getHex(),"address"=>$ethAddress];
			} else {
				$pubKeyHash = $childKey->getPublicKey()->getPubKeyHash();
				$details[$relativePath . $index] = ["decompressed_pub"=>$dePublicKey->getHex(), "compressed_pub"=>$publicKey->getHex(),"address"=>(new PayToPubKeyHashAddress($pubKeyHash))->getAddress()];
			}
		}
		
	} catch (Exception $e) {
        $errmsg .= "Problem found. " . $e->getMessage();
    }
}
if ($errmsg) {
?>
	<div class="alert alert-danger">
		<strong>Error!</strong> <?php echo $errmsg?>
	</div>
<?php
}
if ($details) {
?>
	<h5>Address Array</h5>
	<div class="table-responsive">
		<table class="table table-bordered">
			<tr><th>Full Relative Path</th><th>Address</th><th>Public Key</th></tr>
		<?php 
		foreach($details as $index => $detail) {
		?>
			<tr><td><?php echo $index?></td><td><?php echo $detail['address']?></td><td><p>Compressed:<br/><?php echo $detail['compressed_pub']?></p><p>Decompressed:<br/><?php echo $detail['decompressed_pub']?></p></td></tr>
		<?php
		}
		?>
		</table>
	</div>
<?php
}
?>
<form action='' method='post'>
	<div class="form-group">
        <label for="network">Network *:</label>
        <select id="network" name="network" class="form-control" >
            <?php
            $networks = get_class_methods(new NetworkFactory());
            foreach($networks as $network) {
                echo "<option value='{$network}'".($network == $_POST['network'] ? " selected": "").">{$network}</option>";
            }
			
			$network = "ethereum";
			echo "<option value='{$network}'".($network == $_POST['network'] ? " selected": "").">{$network}</option>";
            ?>
        </select>
    </div>
	
	<div class="form-group">
		<label for="xpub">Bip32 Extended Public Key (Xpub) *:</label>
		
		<div class="input-group mb-3">
			<input class="form-control" type='text' name='xpub' id='xpub' value='<?php echo $_POST['xpub']?>'>
		</div>
	</div>
	
	<div class="form-group">
        <label for="from_index">From Index *:</label>
        <input class="form-control" type='text' name='from_index' id='from_index' value='<?php echo $_POST['from_index']?>'>
        
    </div>
	
	<div class="form-group">
        <label for="to_index">To Index *:</label>
        <input class="form-control" type='text' name='to_index' id='to_index' value='<?php echo $_POST['to_index']?>'>
    </div>
	
	<div class="form-group">
		<label for="relative_path">Relative Path :</label>
		<input class="form-control" type='text' name='relative_path' id='relative_path' value='<?php echo htmlentities($_POST['relative_path'],ENT_QUOTES)?>'>
		* Do not start with /, this field is optional.
	</div>
	
	
	<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php 
include_once("html_iframe_footer.php");