Created
November 22, 2014 16:25
-
-
Save rubensayshi/16d70b66f888442ff8a6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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