* @copyright Copyright (c) 2013 by Core Developer Team * @license See LICENSE (public-domain) */ /** * Calculates a simple but stronger hash from given string. No salts are being * added here. * * @param $str The string to be hashed * @return $hash The hash from string $str */ function hashString ($str) { // Calculate strong hash from given string $hash = mhash(HASH_ALGO, $str); // Return it hexadecimal-encoded return bin2hex($hash); } /** * Double-hashes given string. This is done by hashing the given string and * then hashing the generated hash again. * * @param $str The string to be hashed 4 times * @return $hash The generated hash */ function doubleHashString ($str) { // Generate hash from given hash $hash = hashString(hashString($str)); // Return it return $hash; } /** * Calculates a "modula-hash" based given two hashes. * * @param $hash1 Hash 1 * @param $hash2 Hash 2 */ function modulaHash ($hash1, $hash2) { // Both must have same length assert(strlen($hash1) === strlen($hash2)); // Init new hash $modulaHash = ''; // "Walk" trough first hash and get every 2 byte of both hashes for ($idx = 0; $idx < strlen($hash1); $idx += 2) { // Init modula value $mod = 0; // Get both hash parts and convert to ASCII number $part1 = hexdec(substr($hash1, $idx, 2)); $part2 = hexdec(substr($hash2, $idx, 2)); /* * If part1 is larget part2, part1 is divident and vise-versa. But don't do it * if one is zero */ if (($part1 > $part2) && ($part2 > 0)) { // 'part1' is larger than 'part2' $mod = $part1 % $part2; } elseif (($part1 < $part2) && ($part1 > 0)) { // 'part2' is larger than 'part1' $mod = $part2 % $part1; } // "Invert" the result against 255 $mod = 255 - $mod; // Encode to hex, pre-pad it with zeros and add to new hash $modulaHash .= padHex($mod); } // END - for // Modula hash must have same length as input hash assert(strlen($modulaHash) === strlen($hash1)); // Return modula hash return $modulaHash; } /** * Calculates a "sqrt-hash" based given two hashes and single-hash it * * @param $hash1 Hash 1 * @param $hash2 Hash 2 */ function sqrtHash ($hash1, $hash2) { // Both must have same length assert(strlen($hash1) === strlen($hash2)); // Init new hash $sqrtHash = ''; // "Walk" trough first hash and get every 2 byte of both hashes for ($idx = 0; $idx < strlen($hash1); $idx += 2) { // Init modula value $mod = 0; // Get both hash parts and convert to ASCII number $part1 = hexdec(substr($hash1, $idx, 2)); $part2 = hexdec(substr($hash2, $idx, 2)); // Calculate square root of both parts being multiplied and round up, then "invert" it against 255 $sqrt = intval(255 - ceil(sqrt($part1 * $part2))); // Encode to hex, pre-pad it with zeros and add to new hash $sqrtHash .= padHex($sqrt); } // END - for // "sqrt-hash" must have same length as input hash assert(strlen($sqrtHash) === strlen($hash1)); // Hash reversed "sqrt-hash" again and return it return hashString(strrev($sqrtHash)); } /** * Converts a number between 0 and 255 into a zero-padded hexadecimal string * * @param $num Number between 0 and 255 * @return $hex Hexadecimal string, padded with zeros */ function padHex ($num) { // Must be a integer number and between 0 and 255 assert(is_int($num)); assert($num >= 0); assert($num <= 255); // Convert it $hex = str_pad(dechex($num), 2, '0', STR_PAD_LEFT); // ... and return it return $hex; } /** * Calculates sum from given hash * * @param $hash Hash to calculate sum from * @return $sum Sum from given hash */ function calculateSumFromHash ($hash) { // Everything starts with zero ... $sum = 0; // Loop through hash for ($idx = 0; $idx < (strlen($hash) / 2); $idx++) { // And add it $sum = $sum + (hexdec(substr($hash, $idx, 2)) * $idx & 256); } // END - for // And return it return $sum; } /** * Calculates new nonce * * @param $nonce Old nonce to be used * @return $newNonce New nonce */ function calculateNonce ($nonce) { // Linear incrementation $newNonce = $nonce + NONCE_INCREMENT; // Return new value return $newNonce; } /* * Calculate "genesis" hashes, please note that these "genesis strings" are now * known to the public as you can read them here in source code and therefore I * will not use them for the real genesis hashes. */ $hashes = array( // A famous quote from Deus Ex 2 - Invisible War doublehashString('"Informations must be free." - AI Helios from Deus Ex'), // My name + URL of my first StatusNet instance doubleHashString('Roland Haeder, https://status.mxchange.org'), // A famous quote from Linus Torwalds doubleHashString('"Software is like sex. Its better when its free." - Linus Torwalds'), // Possible truth ;-) doubleHashString('September 11 is a big lie.'), // GNU is not Uni* doubleHashString('GNU is Not Uni*.'), // WINE is not an emulator doubleHashString('WINE Is Not an Emulator.'), // FlightGear - Fly free! doubleHashString('FlightGear - Fly free!'), // Linus Torwalds Quote doubleHashString('Your code is shit.. your argument is shit.'), ); // Calculate "modula hash" from 1st/4th and 2nd/3rd $modulaHashes = array( // "Block" 0 modulaHash($hashes[0], $hashes[3]), modulaHash($hashes[1], $hashes[2]), // "Block" 1 modulaHash($hashes[4], $hashes[7]), modulaHash($hashes[5], $hashes[6]), ); // Calculate "sqrt hash" $sqrtHashes = array( sqrtHash($modulaHashes[0], $modulaHashes[1]), sqrtHash($modulaHashes[2], $modulaHashes[3]) ); // Calulcate modula hash $modulaHash = doubleHashString(modulaHash($sqrtHashes[0], $sqrtHashes[1])); // This is also the "genesis hash" $genesisHash = $modulaHash; // Output results print ('hashes=' . print_r($hashes, TRUE)); print ('modulaHashes=' . print_r($modulaHashes, TRUE)); print ('sqrtHashes=' . print_r($sqrtHashes, TRUE)); print ('modulaHash=' . $modulaHash . PHP_EOL); // Total reward + hashes $totalReward = 0; $totalHashes = 0; $totalBlocks = 0; // Is the check point there? if (is_readable(CHECK_POINT)) { // Then load it $checkPoint = file_get_contents(CHECK_POINT); // Explode it $data = explode(':', $checkPoint); // Assert on count assert(count($data) == 3); // 1st element is nonce, 2nd hash, 3rd found hashes $nonce = base64_decode($data[0]); $modulaHash = $data[1]; $foundHashes = unserialize(base64_decode($data[2])); } else { // Create nonce (small) $nonce = 1 / mt_rand(); } // Output again print ('modulaHash=' . $modulaHash . PHP_EOL); print ('nonce=' . $nonce . PHP_EOL); print ('found=' . count($foundHashes) . PHP_EOL); // Start "mining" while (TRUE) { // Init hash-per-block counter and hashrate $hashesPerBlock = 0; $hashrate = 0; // Wait for BLOCK_SIZE iterations (= found hashes). This is one block $timeBlock = microtime(TRUE); $timeDisplay = $timeBlock; $timeFlush = $timeBlock; // Time waited for a good block again (no iteration) $timeBadHashes = 0; while (count($foundHashes) <= BLOCK_SIZE) { // Create hash from modulaHash ("genesis hash") and nonce $nonceHash = doubleHashString($modulaHash . $nonce); // Calculate sums $sumNonce = calculateSumFromHash($nonceHash); $sumModula = calculateSumFromHash($modulaHash); // Init counter $iter = 0; $iterSecond = 0; // Now start the "mining" ... $timeHash = microtime(TRUE); while ($sumNonce >= $sumModula) { // Calculate new nonce $nonce = calculateNonce($nonce); // And hash again $nonceHash = doubleHashString($modulaHash . $nonce); // Calculate sums $sumNonce = calculateSumFromHash($nonceHash); // Time spend in loop $testTime = abs(microtime(TRUE) - $timeDisplay); // Calculate hashrate/sec $hashrate = 1 / $testTime * $iterSecond * 2; // Only every second if ($testTime >= 1) { // Display hash rate print ('hashrate=' . $hashrate . ' hashes/sec,iterSecond=' . $iterSecond . ' iterations/sec' . PHP_EOL); // Reset timer $timeDisplay = microtime(TRUE); $iterSecond = 0; } // END - if // Time spend from last flush $testTime = abs(microtime(TRUE) - $timeFlush); // Only once per 10 seconds if ($testTime >= 10) { // Display message print ('FLUSHING: ' . count($foundHashes) . ' total found.' . PHP_EOL); // Write check-point file_put_contents(CHECK_POINT, base64_encode($nonce) . ':' . $modulaHash . ':' . base64_encode(serialize($foundHashes))); $timeFlush = microtime(TRUE); } // END - if // Next round $iter++; $iterSecond++; //print ('nonce=' . $nonce . ',iter=' . $iter . PHP_EOL); //print ('nonceHash=' . $nonceHash . PHP_EOL); //print ('sumNonce=' . $sumNonce . PHP_EOL); //print ('sumModula=' . $sumModula . PHP_EOL); } // END - while // If the iteration is zero, then no hash is found if ($iter == 0) { // Bad hash found $timeBadHashes += abs(microtime(TRUE) - $timeHash); // And next round //print('BAD:nonce=' . $nonce . PHP_EOL); // Nothing found, so calculate new nonce $nonce = calculateNonce($nonce); continue; } // END - if // Add amount of hashes per block (double-hash) $hashesPerBlock += $iter * 2 + 2; // Push found hash array_push($foundHashes, array( 'modula_hash' => $modulaHash, 'genesis_hash' => $genesisHash, 'nonce' => $nonce, 'iter' => $iter, 'hashes_block' => $hashesPerBlock, 'nonce_hash' => $nonceHash )); // Found hash: print ('FOUND: nonceHash=' . $nonceHash . ',nonce=' . $nonce . ',iter=' . $iter . PHP_EOL); // Use nonceHash as next modula hash $modulaHash = $nonceHash; } // END - while // Time taken for one block $timeBlock = abs(microtime(TRUE) - $timeBlock); // Calculate reward $reward = abs($timeBlock - $timeBadHashes) / $hashrate * $hashesPerBlock / BLOCK_SIZE * 1000; print ('timeBlock=' . $timeBlock . ',timeBadHashes=' . $timeBadHashes . ',hashesPerBlock=' . $hashesPerBlock .',reward=' . $reward . PHP_EOL); // Block completed $totalHashes += $hashesPerBlock; $totalBlocks++; $hashesPerBlock = 0; $foundHashes = array(); // Calculate new nonce $nonce = calculateNonce($nonce); // Add reward to total $totalReward += $reward; // Calculate average block value $blockValue = $totalReward / $totalBlocks * $totalHashes / (BLOCK_SIZE * $totalBlocks); // Calculate reward per hour (= 3600 seconds) $rewardPerHour = $totalReward / abs(microtime(TRUE) - START_TIME) * 3600; print ('totalReward=' . $totalReward . ',blockValue=' . $blockValue . ',rewardPerHour=' . $rewardPerHour . PHP_EOL); } // END - while // [EOF] ?>