2 error_reporting(E_ALL | E_STRICT);
4 define('HASH_ALGO' , MHASH_RIPEMD320);
5 define('BLOCK_SIZE' , 100);
6 define('NONCE_INCREMENT', 0.0000000000000001);
7 define('START_TIME' , microtime(TRUE));
8 define('CHECK_POINT' , 'chash.pos');
11 $GLOBALS['cycles'] = 3;
14 $GLOBALS['found_hashes'] = array(0 => array());
19 * @author Roland Haeder <roland@mxchange.org>
20 * @copyright Copyright (c) 2013 by Core Developer Team
21 * @license See LICENSE (public-domain)
25 * Calculates a simple but stronger hash from given string. No salts are being
28 * @param $str The string to be hashed
29 * @return $hash The hash from string $str
31 function hashString ($str) {
32 // Calculate strong hash from given string
33 $hash = mhash(HASH_ALGO, $str);
35 // Return it hexadecimal-encoded
36 return bin2hex($hash);
40 * Multiple-hashes given string. This is done by hashing the given string and
41 * then hashing the generated hash again.
43 * @param $str The string to be hashed 4 times
44 * @return $hash The generated hash
46 function multipleHashString ($str) {
47 // One less to go (see below)
48 $totalHashes = $GLOBALS['cycles'] - 1;
50 // Generate hash from given hash
51 $hash = hashString($str);
54 for ($idx = 0; $idx < $totalHashes; $idx++) {
55 // Over-hash the given hash
56 $hash = hashString($hash . $str);
64 * Calculates a "modula-hash" based given two hashes.
66 * @param $hash1 Hash 1
67 * @param $hash2 Hash 2
69 function modulaHash ($hash1, $hash2) {
70 // Both must have same length
71 assert(strlen($hash1) === strlen($hash2));
76 // "Walk" trough first hash and get every 2 byte of both hashes
77 for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
81 // Get both hash parts and convert to ASCII number
82 $part1 = hexdec(substr($hash1, $idx, 2));
83 $part2 = hexdec(substr($hash2, $idx, 2));
86 * If part1 is larget part2, part1 is divident and vise-versa. But don't do it
89 if (($part1 > $part2) && ($part2 > 0)) {
90 // 'part1' is larger than 'part2'
91 $mod = $part1 % $part2;
92 } elseif (($part1 < $part2) && ($part1 > 0)) {
93 // 'part2' is larger than 'part1'
94 $mod = $part2 % $part1;
97 // "Invert" the result against 255
100 // Encode to hex, pre-pad it with zeros and add to new hash
101 $modulaHash .= padHex($mod);
104 // Modula hash must have same length as input hash
105 assert(strlen($modulaHash) === strlen($hash1));
107 // Return modula hash
112 * Calculates a "sqrt-hash" based given two hashes and single-hash it
114 * @param $hash1 Hash 1
115 * @param $hash2 Hash 2
117 function sqrtHash ($hash1, $hash2) {
118 // Both must have same length
119 assert(strlen($hash1) === strlen($hash2));
124 // "Walk" trough first hash and get every 2 byte of both hashes
125 for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
129 // Get both hash parts and convert to ASCII number
130 $part1 = hexdec(substr($hash1, $idx, 2));
131 $part2 = hexdec(substr($hash2, $idx, 2));
133 // Calculate square root of both parts being multiplied and round up, then "invert" it against 255
134 $sqrt = intval(255 - ceil(sqrt($part1 * $part2)));
136 // Encode to hex, pre-pad it with zeros and add to new hash
137 $sqrtHash .= padHex($sqrt);
140 // "sqrt-hash" must have same length as input hash
141 assert(strlen($sqrtHash) === strlen($hash1));
143 // Hash reversed "sqrt-hash" again and return it
144 return hashString(strrev($sqrtHash));
148 * Converts a number between 0 and 255 into a zero-padded hexadecimal string
150 * @param $num Number between 0 and 255
151 * @return $hex Hexadecimal string, padded with zeros
153 function padHex ($num) {
154 // Must be a integer number and between 0 and 255
155 assert(is_int($num));
160 $hex = str_pad(dechex($num), 2, '0', STR_PAD_LEFT);
167 * Calculates sum from given hash
169 * @param $hash Hash to calculate sum from
170 * @return $sum Sum from given hash
172 function calculateSumFromHash ($hash) {
173 // Everything starts with zero ...
177 for ($idx = 0; $idx < (strlen($hash) / 2); $idx++) {
179 $sum = $sum + (hexdec(substr($hash, $idx, 2)) * $idx & 256);
187 * Calculates new nonce
189 * @param $nonce Old nonce to be used
190 * @return $newNonce New nonce
192 function calculateNonce ($nonce) {
193 // Linear incrementation
194 $newNonce = $nonce + NONCE_INCREMENT;
201 * Writes/flushes check-point file
203 * @param $nonce Nonce
204 * @param $modulaHash Modula hash (or hash to save)
207 function flushCheckPointFile ($nonce, $modulaHash) {
209 print ('FLUSHING: Writing ' . count($GLOBALS['found_hashes']) . ' blocks ...' . PHP_EOL);
212 $timer = microtime(TRUE);
215 file_put_contents(CHECK_POINT, $GLOBALS['total_blocks'] . ':' . $GLOBALS['total_hashes'] . ':' . $GLOBALS['cycles'] . ':' . base64_encode($nonce) . ':' . $modulaHash . ':' . base64_encode(serialize($GLOBALS['found_hashes'])));
218 $GLOBALS['time_flush'] = microtime(TRUE);
219 print ('FLUSHING: Took ' . ($GLOBALS['time_flush'] - $timer) . ' seconds.' . PHP_EOL);
223 * Calculate "genesis" hashes, please note that these "genesis strings" are now
224 * known to the public as you can read them here in source code and therefore I
225 * will not use them for the real genesis hashes.
227 $gensisHashes = array(
228 // A famous quote from Deus Ex 2 - Invisible War
229 multiplehashString('"Informations must be free." - AI Helios from Deus Ex'),
230 // My name + URL of my first StatusNet instance
231 multipleHashString('Roland Haeder, https://status.mxchange.org'),
232 // A famous quote from Linus Torwalds
233 multipleHashString('"Software is like sex. Its better when its free." - Linus Torwalds'),
234 // Possible truth ;-)
235 multipleHashString('September 11 is a big lie.'),
238 multipleHashString('GNU is Not Uni*.'),
239 // WINE is not an emulator
240 multipleHashString('WINE Is Not an Emulator.'),
241 // FlightGear - Fly free!
242 multipleHashString('FlightGear - Fly free!'),
243 // Linus Torwalds Quote
244 multipleHashString('Your code is shit.. your argument is shit.'),
247 // Calculate "modula hash" from 1st/4th and 2nd/3rd
248 $modulaHashes = array(
250 modulaHash($gensisHashes[0], $gensisHashes[3]),
251 modulaHash($gensisHashes[1], $gensisHashes[2]),
254 modulaHash($gensisHashes[4], $gensisHashes[7]),
255 modulaHash($gensisHashes[5], $gensisHashes[6]),
258 // Calculate "sqrt hash"
260 sqrtHash($modulaHashes[0], $modulaHashes[1]),
261 sqrtHash($modulaHashes[2], $modulaHashes[3])
264 // Calulcate modula hash
265 $modulaHash = multipleHashString(modulaHash($sqrtHashes[0], $sqrtHashes[1]));
267 // This is also the "genesis hash"
268 $genesisHash = $modulaHash;
271 print ('hashes=' . print_r($gensisHashes, TRUE));
272 print ('modulaHashes=' . print_r($modulaHashes, TRUE));
273 print ('sqrtHashes=' . print_r($sqrtHashes, TRUE));
274 print ('modulaHash=' . $modulaHash . PHP_EOL);
276 // Total reward + hashes
278 $GLOBALS['total_hashes'] = 0;
279 $GLOBALS['total_blocks'] = 0;
281 // Is the check point there?
282 if (is_readable(CHECK_POINT)) {
284 $checkPoint = file_get_contents(CHECK_POINT);
287 $data = explode(':', $checkPoint);
290 assert(count($data) == 6);
292 // 1st element is nonce, 2nd hash, 3rd found hashes
293 $GLOBALS['total_blocks'] = $data[0];
294 $GLOBALS['total_hashes'] = $data[1];
295 $GLOBALS['cycles'] = intval($data[2]);
296 $nonce = base64_decode($data[3]);
297 $modulaHash = $data[4];
298 $GLOBALS['found_hashes'][$GLOBALS['total_blocks']] = unserialize(base64_decode($data[5]));
300 // Create nonce (small)
301 $nonce = 1 / mt_rand();
305 print ('modulaHash=' . $modulaHash . PHP_EOL);
306 print ('nonce=' . $nonce . PHP_EOL);
307 print ('found=' . count($GLOBALS['found_hashes'][$GLOBALS['total_blocks']]) . PHP_EOL);
311 // Init hash-per-block counter and hashrate
315 // Wait for BLOCK_SIZE iterations (= found hashes). This is one block
316 $timeBlock = microtime(TRUE);
317 $timeDisplay = $timeBlock;
318 $GLOBALS['time_flush'] = $timeBlock;
320 // Time waited for a good block again (no iteration)
323 while (count($GLOBALS['found_hashes'][$GLOBALS['total_blocks']]) <= BLOCK_SIZE) {
324 // Create hash from modulaHash ("genesis hash") and nonce
325 $nonceHash = multipleHashString($modulaHash . $nonce);
328 $sumNonce = calculateSumFromHash($nonceHash);
329 $sumModula = calculateSumFromHash($modulaHash);
335 // Now start the "mining" ...
336 $timeHash = microtime(TRUE);
337 while ($sumNonce >= $sumModula) {
338 // Calculate new nonce
339 $nonce = calculateNonce($nonce);
342 $nonceHash = multipleHashString($modulaHash . $nonce);
345 $sumNonce = calculateSumFromHash($nonceHash);
347 // Time spend in loop
348 $testTime = abs(microtime(TRUE) - $timeDisplay);
350 // Calculate hashrate/sec
351 $hashrate = 1 / $testTime * $iterSecond * $GLOBALS['cycles'];
354 if ($testTime >= 1) {
356 print ('hashrate=' . $hashrate . ' hashes/sec,iterSecond=' . $iterSecond . ' iterations/sec' . PHP_EOL);
359 $timeDisplay = microtime(TRUE);
363 // Time spend from last flush
364 $testTime = abs(microtime(TRUE) - $GLOBALS['time_flush']);
366 // Only once per 10 seconds
367 if ($testTime >= 10) {
368 // Flush check-point file
369 flushCheckPointFile($nonce, $modulaHash);
375 //print ('nonce=' . $nonce . ',iter=' . $iter . PHP_EOL);
376 //print ('nonceHash=' . $nonceHash . PHP_EOL);
377 //print ('sumNonce=' . $sumNonce . PHP_EOL);
378 //print ('sumModula=' . $sumModula . PHP_EOL);
381 // If the iteration is zero, then no hash is found
384 $timeBadHashes += abs(microtime(TRUE) - $timeHash);
387 //print('BAD:nonce=' . $nonce . PHP_EOL);
389 // Nothing found, so calculate new nonce
390 $nonce = calculateNonce($nonce);
394 // Add amount of hashes per block (multiple-hash)
395 $hashesPerBlock += $iter * $GLOBALS['cycles'] + $GLOBALS['cycles'];
398 array_push($GLOBALS['found_hashes'][$GLOBALS['total_blocks']], array(
399 'modula_hash' => $modulaHash,
400 'genesis_hash' => $genesisHash,
403 'hashes_block' => $hashesPerBlock,
404 'nonce_hash' => $nonceHash
408 print ('FOUND: nonceHash=' . $nonceHash . ',nonce=' . $nonce . ',iter=' . $iter . PHP_EOL);
410 // Flush check-point file after new hash is found
411 flushCheckPointFile($nonce, $nonceHash);
413 // Use nonceHash as next modula hash
414 $modulaHash = $nonceHash;
417 // Time taken for one block
418 $timeBlock = abs(microtime(TRUE) - $timeBlock);
421 $reward = abs($timeBlock - $timeBadHashes) / $hashrate * $hashesPerBlock / BLOCK_SIZE * 1000;
422 print ('timeBlock=' . $timeBlock . ',timeBadHashes=' . $timeBadHashes . ',hashesPerBlock=' . $hashesPerBlock .',reward=' . $reward . PHP_EOL);
425 $GLOBALS['total_hashes'] += $hashesPerBlock;
426 $GLOBALS['total_blocks']++;
430 $GLOBALS['found_hashes'][$GLOBALS['total_blocks']] = array();
432 // Calculate new nonce
433 $nonce = calculateNonce($nonce);
435 // Add reward to total
436 $totalReward += $reward;
438 // Calculate average block value
439 $blockValue = $totalReward / $GLOBALS['total_blocks'] * $GLOBALS['total_hashes'] / (BLOCK_SIZE * $GLOBALS['total_blocks']);
441 // Calculate reward per hour (= 3600 seconds)
442 $rewardPerHour = $totalReward / abs(microtime(TRUE) - START_TIME) * 3600;
444 print ('totalReward=' . $totalReward . ',blockValue=' . $blockValue . ',rewardPerHour=' . $rewardPerHour . PHP_EOL);