diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php index 28dddb4b..b98bbc3a 100755 --- a/cronjobs/findblock.php +++ b/cronjobs/findblock.php @@ -68,11 +68,12 @@ if (empty($aAllBlocks)) { $log->logDebug('No new blocks without share_id found in database'); } else { // Loop through our unaccounted blocks - $log->logInfo("Block ID\t\tHeight\tAmount\tShare ID\tShares\tFinder"); + $log->logInfo("Block ID\t\tHeight\tAmount\tShare ID\tShares\tFinder\tType"); foreach ($aAllBlocks as $iIndex => $aBlock) { if (empty($aBlock['share_id'])) { // Fetch this blocks upstream ID - if ($share->setUpstream($block->getLastUpstreamId(), $aBlock['time'])) { + $aBlockInfo = $bitcoin->query('getblock', $aBlock['blockhash']); + if ($share->setUpstream($aBlockInfo, $block->getLastUpstreamId())) { $iCurrentUpstreamId = $share->getUpstreamId(); $iAccountId = $user->getUserId($share->getUpstreamFinder()); } else { @@ -104,7 +105,8 @@ if (empty($aAllBlocks)) { . $aBlock['amount'] . "\t" . $iCurrentUpstreamId . "\t\t" . $iRoundShares . "\t" - . "[$iAccountId] " . $user->getUserName($iAccountId) + . "[$iAccountId] " . $user->getUserName($iAccountId) . "\t" + . $share->share_type ); // Notify users diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index c74fa62b..68109049 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -33,3 +33,4 @@ require_once(CLASS_DIR . '/mail.class.php'); require_once(CLASS_DIR . '/notification.class.php'); require_once(CLASS_DIR . '/news.class.php'); require_once(INCLUDE_DIR . '/lib/Michelf/Markdown.php'); +require_once(INCLUDE_DIR . '/lib/scrypt.php'); diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php index 5e4db85e..496652f0 100644 --- a/public/include/classes/share.class.php +++ b/public/include/classes/share.class.php @@ -177,7 +177,48 @@ class Share { * @param last int Skips all shares up to last to find new share * @return bool **/ - public function setUpstream($last=0, $time=0) { + public function setUpstream($aBlock, $last=0) { + // Many use stratum, so we create our stratum check first + $version = pack("I*", sprintf('%08d', $aBlock['version'])); + $previousblockhash = pack("H*", swapEndian($aBlock['previousblockhash'])); + $merkleroot = pack("H*", swapEndian($aBlock['merkleroot']) ); + $time = pack("I*", $aBlock['time']); + $bits = pack("H*", swapEndian($aBlock['bits'])); + $nonce = pack("I*", $aBlock['nonce']); + $header_bin = $version . $previousblockhash . $merkleroot . $time . $bits . $nonce; + $header_hex = implode(unpack("H*", $header_bin)); + + // Stratum supported blockhash solution entry + $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution = ? LIMIT 1"); + if ($this->checkStmt($stmt) && $stmt->bind_param('s', $aBlock['hash']) && $stmt->execute() && $result = $stmt->get_result()) { + $this->oUpstream = $result->fetch_object(); + $this->share_type = 'startum_blockhash'; + if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id)) + return true; + } + + // Stratum scrypt hash check + $scrypt_hash = swapEndian(bin2hex(Scrypt::calc($header_bin, $header_bin, 1024, 1, 1, 32))); + $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution = ? LIMIT 1"); + if ($this->checkStmt($stmt) && $stmt->bind_param('s', $scrypt_hash) && $stmt->execute() && $result = $stmt->get_result()) { + $this->oUpstream = $result->fetch_object(); + $this->share_type = 'startum_solution'; + if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id)) + return true; + } + + // Failed to fetch via startum solution, try pushpoold + // Fallback to pushpoold solution type + $ppheader = sprintf('%08d', $aBlock['version']) . word_reverse($aBlock['previousblockhash']) . word_reverse($aBlock['merkleroot']) . dechex($aBlock['time']) . $aBlock['bits'] . dechex($aBlock['nonce']); + $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution LIKE CONCAT(?, '%') LIMIT 1"); + if ($this->checkStmt($stmt) && $stmt->bind_param('s', $ppheader) && $stmt->execute() && $result = $stmt->get_result()) { + $this->oUpstream = $result->fetch_object(); + $this->share_type = 'pp_solution'; + if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id)) + return true; + } + + // Still no match, try upstream result with timerange $stmt = $this->mysqli->prepare(" SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id @@ -185,13 +226,16 @@ class Share { WHERE upstream_result = 'Y' AND id > ? AND UNIX_TIMESTAMP(time) >= ? + AND UNIX_TIMESTAMP(time) <= ( ? + 60 ) ORDER BY id ASC LIMIT 1"); - if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $time) && $stmt->execute() && $result = $stmt->get_result()) { + if ($this->checkStmt($stmt) && $stmt->bind_param('iii', $last, $aBlock['time'], $aBlock['time']) && $stmt->execute() && $result = $stmt->get_result()) { $this->oUpstream = $result->fetch_object(); + $this->share_type = 'upstream_share'; if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id)) return true; } - // First attempt failed, we do a fallback with any share available for now + + // We failed again, now we take ANY result matching the timestamp $stmt = $this->mysqli->prepare(" SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id @@ -200,8 +244,9 @@ class Share { AND id > ? AND UNIX_TIMESTAMP(time) >= ? ORDER BY id ASC LIMIT 1"); - if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $time) && $stmt->execute() && $result = $stmt->get_result()) { + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $aBlock['time']) && $stmt->execute() && $result = $stmt->get_result()) { $this->oUpstream = $result->fetch_object(); + $this->share_type = 'any_share'; if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id)) return true; } diff --git a/public/include/lib/scrypt.php b/public/include/lib/scrypt.php new file mode 100644 index 00000000..3d501b7d --- /dev/null +++ b/public/include/lib/scrypt.php @@ -0,0 +1,536 @@ + 0 and a power of 2"); + } + if ($n > PHP_INT_MAX / 128 / $r) { + throw new Exception\InvalidArgumentException("Parameter n is too large"); + } + if ($r > PHP_INT_MAX / 128 / $p) { + throw new Exception\InvalidArgumentException("Parameter r is too large"); + } + + if (extension_loaded('Scrypt')) { + if ($length < 16) { + throw new Exception\InvalidArgumentException("Key length is too low, must be greater or equal to 16"); + } + return self::hex2bin(scrypt($password, $salt, $n, $r, $p, $length)); + } + + $b = Pbkdf2::calc('sha256', $password, $salt, 1, $p * 128 * $r); + + $s = ''; + for ($i = 0; $i < $p; $i++) { + $s .= self::scryptROMix(substr($b, $i * 128 * $r, 128 * $r), $n, $r); + } + + return Pbkdf2::calc('sha256', $password, $s, 1, $length); + } + + /** +* scryptROMix +* +* @param string $b +* @param integer $n +* @param integer $r +* @return string +* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4 +*/ + protected static function scryptROMix($b, $n, $r) + { + $x = $b; + $v = array(); + for ($i = 0; $i < $n; $i++) { + $v[$i] = $x; + $x = self::scryptBlockMix($x, $r); + } + for ($i = 0; $i < $n; $i++) { + $j = self::integerify($x) % $n; + $t = $x ^ $v[$j]; + $x = self::scryptBlockMix($t, $r); + } + return $x; + } + + /** +* scryptBlockMix +* +* @param string $b +* @param integer $r +* @return string +* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-3 +*/ + protected static function scryptBlockMix($b, $r) + { + $x = substr($b, -64); + $even = ''; + $odd = ''; + $len = 2 * $r; + + for ($i = 0; $i < $len; $i++) { + if (PHP_INT_SIZE === 4) { + $x = self::salsa208Core32($x ^ substr($b, 64 * $i, 64)); + } else { + $x = self::salsa208Core64($x ^ substr($b, 64 * $i, 64)); + } + if ($i % 2 == 0) { + $even .= $x; + } else { + $odd .= $x; + } + } + return $even . $odd; + } + + /** +* Salsa 20/8 core (32 bit version) +* +* @param string $b +* @return string +* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2 +* @see http://cr.yp.to/salsa20.html +*/ + protected static function salsa208Core32($b) + { + $b32 = array(); + for ($i = 0; $i < 16; $i++) { + list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4)); + } + + $x = $b32; + for ($i = 0; $i < 8; $i += 2) { + $a = ($x[ 0] + $x[12]); + $x[ 4] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[ 4] + $x[ 0]); + $x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[ 8] + $x[ 4]); + $x[12] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[12] + $x[ 8]); + $x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[ 5] + $x[ 1]); + $x[ 9] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[ 9] + $x[ 5]); + $x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[13] + $x[ 9]); + $x[ 1] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[ 1] + $x[13]); + $x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[10] + $x[ 6]); + $x[14] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[14] + $x[10]); + $x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[ 2] + $x[14]); + $x[ 6] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[ 6] + $x[ 2]); + $x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[15] + $x[11]); + $x[ 3] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[ 3] + $x[15]); + $x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[ 7] + $x[ 3]); + $x[11] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[11] + $x[ 7]); + $x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[ 0] + $x[ 3]); + $x[ 1] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[ 1] + $x[ 0]); + $x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[ 2] + $x[ 1]); + $x[ 3] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[ 3] + $x[ 2]); + $x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[ 5] + $x[ 4]); + $x[ 6] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[ 6] + $x[ 5]); + $x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[ 7] + $x[ 6]); + $x[ 4] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[ 4] + $x[ 7]); + $x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[10] + $x[ 9]); + $x[11] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[11] + $x[10]); + $x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[ 8] + $x[11]); + $x[ 9] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[ 9] + $x[ 8]); + $x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + $a = ($x[15] + $x[14]); + $x[12] ^= ($a << 7) | ($a >> 25) & 0x7f; + $a = ($x[12] + $x[15]); + $x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff; + $a = ($x[13] + $x[12]); + $x[14] ^= ($a << 13) | ($a >> 19) & 0x1fff; + $a = ($x[14] + $x[13]); + $x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff; + } + for ($i = 0; $i < 16; $i++) { + $b32[$i] = $b32[$i] + $x[$i]; + } + $result = ''; + for ($i = 0; $i < 16; $i++) { + $result .= pack("V", $b32[$i]); + } + + return $result; + } + + /** +* Salsa 20/8 core (64 bit version) +* +* @param string $b +* @return string +* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2 +* @see http://cr.yp.to/salsa20.html +*/ + protected static function salsa208Core64($b) + { + $b32 = array(); + for ($i = 0; $i < 16; $i++) { + list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4)); + } + + $x = $b32; + for ($i = 0; $i < 8; $i += 2) { + $a = ($x[ 0] + $x[12]) & 0xffffffff; + $x[ 4] ^= ($a << 7) | ($a >> 25); + $a = ($x[ 4] + $x[ 0]) & 0xffffffff; + $x[ 8] ^= ($a << 9) | ($a >> 23); + $a = ($x[ 8] + $x[ 4]) & 0xffffffff; + $x[12] ^= ($a << 13) | ($a >> 19); + $a = ($x[12] + $x[ 8]) & 0xffffffff; + $x[ 0] ^= ($a << 18) | ($a >> 14); + $a = ($x[ 5] + $x[ 1]) & 0xffffffff; + $x[ 9] ^= ($a << 7) | ($a >> 25); + $a = ($x[ 9] + $x[ 5]) & 0xffffffff; + $x[13] ^= ($a << 9) | ($a >> 23); + $a = ($x[13] + $x[ 9]) & 0xffffffff; + $x[ 1] ^= ($a << 13) | ($a >> 19); + $a = ($x[ 1] + $x[13]) & 0xffffffff; + $x[ 5] ^= ($a << 18) | ($a >> 14); + $a = ($x[10] + $x[ 6]) & 0xffffffff; + $x[14] ^= ($a << 7) | ($a >> 25); + $a = ($x[14] + $x[10]) & 0xffffffff; + $x[ 2] ^= ($a << 9) | ($a >> 23); + $a = ($x[ 2] + $x[14]) & 0xffffffff; + $x[ 6] ^= ($a << 13) | ($a >> 19); + $a = ($x[ 6] + $x[ 2]) & 0xffffffff; + $x[10] ^= ($a << 18) | ($a >> 14); + $a = ($x[15] + $x[11]) & 0xffffffff; + $x[ 3] ^= ($a << 7) | ($a >> 25); + $a = ($x[ 3] + $x[15]) & 0xffffffff; + $x[ 7] ^= ($a << 9) | ($a >> 23); + $a = ($x[ 7] + $x[ 3]) & 0xffffffff; + $x[11] ^= ($a << 13) | ($a >> 19); + $a = ($x[11] + $x[ 7]) & 0xffffffff; + $x[15] ^= ($a << 18) | ($a >> 14); + $a = ($x[ 0] + $x[ 3]) & 0xffffffff; + $x[ 1] ^= ($a << 7) | ($a >> 25); + $a = ($x[ 1] + $x[ 0]) & 0xffffffff; + $x[ 2] ^= ($a << 9) | ($a >> 23); + $a = ($x[ 2] + $x[ 1]) & 0xffffffff; + $x[ 3] ^= ($a << 13) | ($a >> 19); + $a = ($x[ 3] + $x[ 2]) & 0xffffffff; + $x[ 0] ^= ($a << 18) | ($a >> 14); + $a = ($x[ 5] + $x[ 4]) & 0xffffffff; + $x[ 6] ^= ($a << 7) | ($a >> 25); + $a = ($x[ 6] + $x[ 5]) & 0xffffffff; + $x[ 7] ^= ($a << 9) | ($a >> 23); + $a = ($x[ 7] + $x[ 6]) & 0xffffffff; + $x[ 4] ^= ($a << 13) | ($a >> 19); + $a = ($x[ 4] + $x[ 7]) & 0xffffffff; + $x[ 5] ^= ($a << 18) | ($a >> 14); + $a = ($x[10] + $x[ 9]) & 0xffffffff; + $x[11] ^= ($a << 7) | ($a >> 25); + $a = ($x[11] + $x[10]) & 0xffffffff; + $x[ 8] ^= ($a << 9) | ($a >> 23); + $a = ($x[ 8] + $x[11]) & 0xffffffff; + $x[ 9] ^= ($a << 13) | ($a >> 19); + $a = ($x[ 9] + $x[ 8]) & 0xffffffff; + $x[10] ^= ($a << 18) | ($a >> 14); + $a = ($x[15] + $x[14]) & 0xffffffff; + $x[12] ^= ($a << 7) | ($a >> 25); + $a = ($x[12] + $x[15]) & 0xffffffff; + $x[13] ^= ($a << 9) | ($a >> 23); + $a = ($x[13] + $x[12]) & 0xffffffff; + $x[14] ^= ($a << 13) | ($a >> 19); + $a = ($x[14] + $x[13]) & 0xffffffff; + $x[15] ^= ($a << 18) | ($a >> 14); + } + for ($i = 0; $i < 16; $i++) { + $b32[$i] = ($b32[$i] + $x[$i]) & 0xffffffff; + } + $result = ''; + for ($i = 0; $i < 16; $i++) { + $result .= pack("V", $b32[$i]); + } + + return $result; + } + + /** +* Integerify +* +* Integerify (B[0] ... B[2 * r - 1]) is defined as the result +* of interpreting B[2 * r - 1] as a little-endian integer. +* Each block B is a string of 64 bytes. +* +* @param string $b +* @return integer +* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4 +*/ + protected static function integerify($b) + { + $v = 'v'; + if (PHP_INT_SIZE === 8) { + $v = 'V'; + } + list(,$n) = unpack($v, substr($b, -64)); + return $n; + } + + /** +* Convert hex string in a binary string +* +* @param string $hex +* @return string +*/ + protected static function hex2bin($hex) + { + if (version_compare(PHP_VERSION, '5.4') >= 0) { + return hex2bin($hex); + } + $len = strlen($hex); + $result = ''; + for ($i = 0; $i < $len; $i+=2) { + $result .= chr(hexdec($hex[$i] . $hex[$i+1])); + } + return $result; + } +} + + + +/** +* Zend Framework (http://framework.zend.com/) +* +* @link http://github.com/zendframework/zf2 for the canonical source repository +* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) +* @license http://framework.zend.com/license/new-bsd New BSD License +*/ + + + + + +/** +* PKCS #5 v2.0 standard RFC 2898 +*/ +class Pbkdf2 +{ + /** +* Generate the new key +* +* @param string $hash The hash algorithm to be used by HMAC +* @param string $password The source password/key +* @param string $salt +* @param integer $iterations The number of iterations +* @param integer $length The output size +* @throws Exception\InvalidArgumentException +* @return string +*/ + public static function calc($hash, $password, $salt, $iterations, $length) + { + if (!Hmac::isSupported($hash)) { + throw new Exception\InvalidArgumentException("The hash algorithm $hash is not supported by " . __CLASS__); + } + + $num = ceil($length / Hmac::getOutputSize($hash, Hmac::OUTPUT_BINARY)); + $result = ''; + for ($block = 1; $block <= $num; $block++) { + $hmac = hash_hmac($hash, $salt . pack('N', $block), $password, Hmac::OUTPUT_BINARY); + $mix = $hmac; + for ($i = 1; $i < $iterations; $i++) { + $hmac = hash_hmac($hash, $hmac, $password, Hmac::OUTPUT_BINARY); + $mix ^= $hmac; + } + $result .= $mix; + } + return substr($result, 0, $length); + } +} + + + +/** +* Zend Framework (http://framework.zend.com/) +* +* @link http://github.com/zendframework/zf2 for the canonical source repository +* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) +* @license http://framework.zend.com/license/new-bsd New BSD License +*/ + + + +/** +* PHP implementation of the RFC 2104 Hash based Message Authentication Code +*/ +class Hmac +{ + const OUTPUT_STRING = false; + const OUTPUT_BINARY = true; + + /** +* Last algorithm supported +* +* @var string|null +*/ + protected static $lastAlgorithmSupported; + + /** +* Performs a HMAC computation given relevant details such as Key, Hashing +* algorithm, the data to compute MAC of, and an output format of String, +* or Binary. +* +* @param string $key +* @param string $hash +* @param string $data +* @param bool $output +* @throws Exception\InvalidArgumentException +* @return string +*/ + public static function compute($key, $hash, $data, $output = self::OUTPUT_STRING) + { + + if (empty($key)) { + throw new Exception\InvalidArgumentException('Provided key is null or empty'); + } + + if (!$hash || ($hash !== static::$lastAlgorithmSupported && !static::isSupported($hash))) { + throw new Exception\InvalidArgumentException( + "Hash algorithm is not supported on this PHP installation; provided '{$hash}'" + ); + } + + return hash_hmac($hash, $data, $key, $output); + } + + /** +* Get the output size according to the hash algorithm and the output format +* +* @param string $hash +* @param bool $output +* @return integer +*/ + public static function getOutputSize($hash, $output = self::OUTPUT_STRING) + { + return strlen(static::compute('key', $hash, 'data', $output)); + } + + /** +* Get the supported algorithm +* +* @return array +*/ + public static function getSupportedAlgorithms() + { + return hash_algos(); + } + + /** +* Is the hash algorithm supported? +* +* @param string $algorithm +* @return bool +*/ + public static function isSupported($algorithm) + { + if ($algorithm === static::$lastAlgorithmSupported) { + return true; + } + + if (in_array(strtolower($algorithm), hash_algos(), true)) { + static::$lastAlgorithmSupported = $algorithm; + return true; + } + + return false; + } + + /** +* Clear the cache of last algorithm supported +*/ + public static function clearLastAlgorithmCache() + { + static::$lastAlgorithmSupported = null; + } +} + function swapEndian($input){ + $output = ""; + for($i=0;$i< strlen($input);$i+=2){ + $output .= substr($input, -($i+2), 2); + + + } + return $output; + + + } + + +/*for($i=0;$i < 200;$i++){ + $value = Scrypt::calc($i, $i, 1024, 1, 1, 32); + echo "scrypt ".$i." hash:". bin2hex($value)."
"; +}*/ +/* +$i = pack("H*", "01000000f615f7ce3b4fc6b8f61e8f89aedb1d0852507650533a9e3b10b9bbcc30639f279fcaa86746e1ef52d3edb3c4ad8259920d509bd073605c9bf1d59983752a6b06b817bb4ea78e011d012d59d4"); + +$value = Scrypt::calc($i, $i, 1024, 1, 1, 32); + echo "scrypt ".$i." hash:". bin2hex($value)."
"; + print_r( swapEndian(bin2hex($value))); + */ + + +// Function used for pushpoold solution checks +function word_reverse($str) { + $ret = ''; + while (strlen($str) > 0) { + $ret .= substr($str, -8, 8); + $str = substr($str, 0, -8); + } + return $ret; +} + +?>