Skip to content

Instantly share code, notes, and snippets.

@rubensayshi
Created November 22, 2014 16:25
Show Gist options
  • Select an option

  • Save rubensayshi/16d70b66f888442ff8a6 to your computer and use it in GitHub Desktop.

Select an option

Save rubensayshi/16d70b66f888442ff8a6 to your computer and use it in GitHub Desktop.
<?php
namespace BlockTrail\Util;
/**
* BaseCoinAddressHelper class
*
* Original By Mike Gogulski - All rights reversed http://www.unlicense.org/ (public domain)
* Modified By Ruben de Vries to remove static methods
* and using inheretance and instances to manage different protocols and versions
*
* @author Ruben de Vries - http://www.blockcorp.com
* @author Mike Gogulski - http://www.nostate.com/ http://www.gogulski.com/
* @author theymos - theymos @ http://bitcoin.org/smf
*/
abstract class BaseCoinAddressHelper {
/*
* hex input must be in uppercase, with no leading 0x
*/
protected static $HEXCHARS = "0123456789ABCDEF";
protected static $BASE58CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
protected $addressversion = "00";
protected $p2saddressversion = "05";
public function __construct($testnet = false) {
$this->addressversion = $this->determineAddressVersion($testnet);
$this->p2saddressversion = $this->determineP2SAddressVersion($testnet);
}
abstract protected function determineAddressVersion($testnet);
abstract protected function determineP2SAddressVersion($testnet);
public function getAddressVersion() {
return $this->addressversion;
}
public function getP2SAddressVersion() {
return $this->p2saddressversion;
}
/**
* Convert a hex string into a (big) integer
*
* @param string $hex
* @return int
* @access protected
*/
protected function decodeHex($hex) {
$hex = strtoupper($hex);
$return = "0";
for ($i = 0; $i < strlen($hex); $i++) {
$current = (string) strpos(self::$HEXCHARS, $hex[$i]);
$return = (string) bcmul($return, "16", 0);
$return = (string) bcadd($return, $current, 0);
}
return $return;
}
/**
* Convert an integer into a hex string
*
* @param int $dec
* @return string
* @access protected
*/
protected function encodeHex($dec) {
$return = "";
while (bccomp($dec, 0) == 1) {
$dv = (string) bcdiv($dec, "16", 0);
$rem = (integer) bcmod($dec, "16");
$dec = $dv;
$return = $return . self::$HEXCHARS[$rem];
}
return strrev($return);
}
/**
* Convert a Base58-encoded integer into the equivalent hex string representation
*
* @param string $base58
* @return string
* @access protected
*/
protected function decodeBase58($base58) {
$origbase58 = $base58;
//only valid chars allowed
if (preg_match('/[^1-9A-HJ-NP-Za-km-z]/', $base58)) {
return "";
}
$return = "0";
for ($i = 0; $i < strlen($base58); $i++) {
$current = (string) strpos(self::$BASE58CHARS, $base58[$i]);
$return = (string) bcmul($return, "58", 0);
$return = (string) bcadd($return, $current, 0);
}
$return = $this->encodeHex($return);
//leading zeros
for ($i = 0; $i < strlen($origbase58) && $origbase58[$i] == "1"; $i++) {
$return = "00" . $return;
}
if (strlen($return) % 2 != 0) {
$return = "0" . $return;
}
return $return;
}
/**
* Convert a hex string representation of an integer into the equivalent Base58 representation
*
* @param string $hex
* @return string
* @access protected
*/
protected function encodeBase58($hex) {
if (strlen($hex) % 2 != 0) {
die("encodeBase58: uneven number of hex characters");
}
$orighex = $hex;
$hex = $this->decodeHex($hex);
$return = "";
while (bccomp($hex, 0) == 1) {
$dv = (string) bcdiv($hex, "58", 0);
$rem = (integer) bcmod($hex, "58");
$hex = $dv;
$return = $return . self::$BASE58CHARS[$rem];
}
$return = strrev($return);
//leading zeros
for ($i = 0; $i < strlen($orighex) && substr($orighex, $i, 2) == "00"; $i += 2) {
$return = "1" . $return;
}
return $return;
}
/**
* Convert a 160-bit Bitcoin hash to a Bitcoin address
*
* @author theymos
* @param string $hash160
* @internal param string $addressversion
* @return string Bitcoin address
* @access public
*/
public function hash160ToAddress($hash160) {
$hash160 = $this->getAddressVersion() . $hash160;
$check = pack("H*", $hash160);
$check = hash("sha256", hash("sha256", $check, true));
$check = substr($check, 0, 8);
$hash160 = strtoupper($hash160 . $check);
return $this->encodeBase58($hash160);
}
/**
* Convert a Bitcoin address to a 160-bit Bitcoin hash
*
* @author theymos
* @param string $addr
* @return string Bitcoin hash
* @access public
*/
public function addressToHash160($addr) {
$addr = $this->decodeBase58($addr);
$addr = substr($addr, 2, strlen($addr) - 10);
return $addr;
}
/**
* Determine if a string is a valid Bitcoin address
*
* @author theymos
* @param string $addr String to test
* @param string $addressversion
* @return boolean
* @access public
*/
public function checkAddress($addr) {
$addr = $this->decodeBase58($addr);
if (strlen($addr) != 50) {
return false;
}
$version = substr($addr, 0, 2);
if (hexdec($version) != hexdec($this->getAddressVersion()) && hexdec($version) != hexdec($this->getP2SAddressVersion())) {
return false;
}
$check = substr($addr, 0, strlen($addr) - 8);
$check = pack("H*", $check);
$check = strtoupper(hash("sha256", hash("sha256", $check, true)));
$check = substr($check, 0, 8);
return $check == substr($addr, strlen($addr) - 8);
}
/**
* Convert the input to its 160-bit Bitcoin hash
*
* @param string $data
* @return string
* @access protected
*/
public function hash160($data) {
$data = pack("H*", $data);
return strtoupper(hash("ripemd160", hash("sha256", $data, true)));
}
/**
* Convert a Bitcoin public key to a 160-bit Bitcoin hash
*
* @param string $pubkey
* @return string
* @access public
*/
public function pubKeyToAddress($pubkey) {
return $this->hash160ToAddress($this->hash160($pubkey));
}
/**
* Remove leading "0x" from a hex value if present.
*
* @param string $string
* @return string
* @access public
*/
public function remove0x($string) {
if (substr($string, 0, 2) == "0x" || substr($string, 0, 2) == "0X") {
$string = substr($string, 2);
}
return $string;
}
}
<?php
namespace BlockTrail\Util;
class BitcoinAddressHelper extends BaseCoinAddressHelper {
protected function determineAddressVersion($testnet) {
return ($testnet) ? "6F" : "00"; //TestNet vs ProductionNet
}
protected function determineP2SAddressVersion($testnet) {
return ($testnet) ? "C4" : "05"; //TestNet vs ProductionNet
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment