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 $foundHashes = array();
13 // Time when last flush occured
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 * Double-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 doubleHashString ($str) {
47 // Generate hash from given hash
48 $hash = hashString(hashString($str));
55 * Calculates a "modula-hash" based given two hashes.
57 * @param $hash1 Hash 1
58 * @param $hash2 Hash 2
60 function modulaHash ($hash1, $hash2) {
61 // Both must have same length
62 assert(strlen($hash1) === strlen($hash2));
67 // "Walk" trough first hash and get every 2 byte of both hashes
68 for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
72 // Get both hash parts and convert to ASCII number
73 $part1 = hexdec(substr($hash1, $idx, 2));
74 $part2 = hexdec(substr($hash2, $idx, 2));
77 * If part1 is larget part2, part1 is divident and vise-versa. But don't do it
80 if (($part1 > $part2) && ($part2 > 0)) {
81 // 'part1' is larger than 'part2'
82 $mod = $part1 % $part2;
83 } elseif (($part1 < $part2) && ($part1 > 0)) {
84 // 'part2' is larger than 'part1'
85 $mod = $part2 % $part1;
88 // "Invert" the result against 255
91 // Encode to hex, pre-pad it with zeros and add to new hash
92 $modulaHash .= padHex($mod);
95 // Modula hash must have same length as input hash
96 assert(strlen($modulaHash) === strlen($hash1));
103 * Calculates a "sqrt-hash" based given two hashes and single-hash it
105 * @param $hash1 Hash 1
106 * @param $hash2 Hash 2
108 function sqrtHash ($hash1, $hash2) {
109 // Both must have same length
110 assert(strlen($hash1) === strlen($hash2));
115 // "Walk" trough first hash and get every 2 byte of both hashes
116 for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
120 // Get both hash parts and convert to ASCII number
121 $part1 = hexdec(substr($hash1, $idx, 2));
122 $part2 = hexdec(substr($hash2, $idx, 2));
124 // Calculate square root of both parts being multiplied and round up, then "invert" it against 255
125 $sqrt = intval(255 - ceil(sqrt($part1 * $part2)));
127 // Encode to hex, pre-pad it with zeros and add to new hash
128 $sqrtHash .= padHex($sqrt);
131 // "sqrt-hash" must have same length as input hash
132 assert(strlen($sqrtHash) === strlen($hash1));
134 // Hash reversed "sqrt-hash" again and return it
135 return hashString(strrev($sqrtHash));
139 * Converts a number between 0 and 255 into a zero-padded hexadecimal string
141 * @param $num Number between 0 and 255
142 * @return $hex Hexadecimal string, padded with zeros
144 function padHex ($num) {
145 // Must be a integer number and between 0 and 255
146 assert(is_int($num));
151 $hex = str_pad(dechex($num), 2, '0', STR_PAD_LEFT);
158 * Calculates sum from given hash
160 * @param $hash Hash to calculate sum from
161 * @return $sum Sum from given hash
163 function calculateSumFromHash ($hash) {
164 // Everything starts with zero ...
168 for ($idx = 0; $idx < (strlen($hash) / 2); $idx++) {
170 $sum = $sum + (hexdec(substr($hash, $idx, 2)) * $idx & 256);
178 * Calculates new nonce
180 * @param $nonce Old nonce to be used
181 * @return $newNonce New nonce
183 function calculateNonce ($nonce) {
184 // Linear incrementation
185 $newNonce = $nonce + NONCE_INCREMENT;
192 * Writes/flushes check-point file
196 function flushCheckPointFile ($nonce, $modulaHash, array $foundHashes) {
200 print ('FLUSHING: ' . count($foundHashes) . ' total found.' . PHP_EOL);
203 file_put_contents(CHECK_POINT, base64_encode($nonce) . ':' . $modulaHash . ':' . base64_encode(serialize($foundHashes)));
206 $timeFlush = microtime(TRUE);
210 * Calculate "genesis" hashes, please note that these "genesis strings" are now
211 * known to the public as you can read them here in source code and therefore I
212 * will not use them for the real genesis hashes.
215 // A famous quote from Deus Ex 2 - Invisible War
216 doublehashString('"Informations must be free." - AI Helios from Deus Ex'),
217 // My name + URL of my first StatusNet instance
218 doubleHashString('Roland Haeder, https://status.mxchange.org'),
219 // A famous quote from Linus Torwalds
220 doubleHashString('"Software is like sex. Its better when its free." - Linus Torwalds'),
221 // Possible truth ;-)
222 doubleHashString('September 11 is a big lie.'),
225 doubleHashString('GNU is Not Uni*.'),
226 // WINE is not an emulator
227 doubleHashString('WINE Is Not an Emulator.'),
228 // FlightGear - Fly free!
229 doubleHashString('FlightGear - Fly free!'),
230 // Linus Torwalds Quote
231 doubleHashString('Your code is shit.. your argument is shit.'),
234 // Calculate "modula hash" from 1st/4th and 2nd/3rd
235 $modulaHashes = array(
237 modulaHash($hashes[0], $hashes[3]),
238 modulaHash($hashes[1], $hashes[2]),
241 modulaHash($hashes[4], $hashes[7]),
242 modulaHash($hashes[5], $hashes[6]),
245 // Calculate "sqrt hash"
247 sqrtHash($modulaHashes[0], $modulaHashes[1]),
248 sqrtHash($modulaHashes[2], $modulaHashes[3])
251 // Calulcate modula hash
252 $modulaHash = doubleHashString(modulaHash($sqrtHashes[0], $sqrtHashes[1]));
254 // This is also the "genesis hash"
255 $genesisHash = $modulaHash;
258 print ('hashes=' . print_r($hashes, TRUE));
259 print ('modulaHashes=' . print_r($modulaHashes, TRUE));
260 print ('sqrtHashes=' . print_r($sqrtHashes, TRUE));
261 print ('modulaHash=' . $modulaHash . PHP_EOL);
263 // Total reward + hashes
268 // Is the check point there?
269 if (is_readable(CHECK_POINT)) {
271 $checkPoint = file_get_contents(CHECK_POINT);
274 $data = explode(':', $checkPoint);
277 assert(count($data) == 3);
279 // 1st element is nonce, 2nd hash, 3rd found hashes
280 $nonce = base64_decode($data[0]);
281 $modulaHash = $data[1];
282 $foundHashes = unserialize(base64_decode($data[2]));
284 // Create nonce (small)
285 $nonce = 1 / mt_rand();
289 print ('modulaHash=' . $modulaHash . PHP_EOL);
290 print ('nonce=' . $nonce . PHP_EOL);
291 print ('found=' . count($foundHashes) . PHP_EOL);
295 // Init hash-per-block counter and hashrate
299 // Wait for BLOCK_SIZE iterations (= found hashes). This is one block
300 $timeBlock = microtime(TRUE);
301 $timeDisplay = $timeBlock;
302 $timeFlush = $timeBlock;
304 // Time waited for a good block again (no iteration)
307 while (count($foundHashes) <= BLOCK_SIZE) {
308 // Create hash from modulaHash ("genesis hash") and nonce
309 $nonceHash = doubleHashString($modulaHash . $nonce);
312 $sumNonce = calculateSumFromHash($nonceHash);
313 $sumModula = calculateSumFromHash($modulaHash);
319 // Now start the "mining" ...
320 $timeHash = microtime(TRUE);
321 while ($sumNonce >= $sumModula) {
322 // Calculate new nonce
323 $nonce = calculateNonce($nonce);
326 $nonceHash = doubleHashString($modulaHash . $nonce);
329 $sumNonce = calculateSumFromHash($nonceHash);
331 // Time spend in loop
332 $testTime = abs(microtime(TRUE) - $timeDisplay);
334 // Calculate hashrate/sec
335 $hashrate = 1 / $testTime * $iterSecond * 2;
338 if ($testTime >= 1) {
340 print ('hashrate=' . $hashrate . ' hashes/sec,iterSecond=' . $iterSecond . ' iterations/sec' . PHP_EOL);
343 $timeDisplay = microtime(TRUE);
347 // Time spend from last flush
348 $testTime = abs(microtime(TRUE) - $timeFlush);
350 // Only once per 10 seconds
351 if ($testTime >= 10) {
352 // Flush check-point file
353 flushCheckPointFile($nonce, $modulaHash, $foundHashes);
359 //print ('nonce=' . $nonce . ',iter=' . $iter . PHP_EOL);
360 //print ('nonceHash=' . $nonceHash . PHP_EOL);
361 //print ('sumNonce=' . $sumNonce . PHP_EOL);
362 //print ('sumModula=' . $sumModula . PHP_EOL);
365 // If the iteration is zero, then no hash is found
368 $timeBadHashes += abs(microtime(TRUE) - $timeHash);
371 //print('BAD:nonce=' . $nonce . PHP_EOL);
373 // Nothing found, so calculate new nonce
374 $nonce = calculateNonce($nonce);
378 // Add amount of hashes per block (double-hash)
379 $hashesPerBlock += $iter * 2 + 2;
382 array_push($foundHashes, array(
383 'modula_hash' => $modulaHash,
384 'genesis_hash' => $genesisHash,
387 'hashes_block' => $hashesPerBlock,
388 'nonce_hash' => $nonceHash
392 print ('FOUND: nonceHash=' . $nonceHash . ',nonce=' . $nonce . ',iter=' . $iter . PHP_EOL);
394 // Flush check-point file after new hash is found
395 flushCheckPointFile($nonce, $nonceHash, $foundHashes);
397 // Use nonceHash as next modula hash
398 $modulaHash = $nonceHash;
401 // Time taken for one block
402 $timeBlock = abs(microtime(TRUE) - $timeBlock);
405 $reward = abs($timeBlock - $timeBadHashes) / $hashrate * $hashesPerBlock / BLOCK_SIZE * 1000;
406 print ('timeBlock=' . $timeBlock . ',timeBadHashes=' . $timeBadHashes . ',hashesPerBlock=' . $hashesPerBlock .',reward=' . $reward . PHP_EOL);
409 $totalHashes += $hashesPerBlock;
412 $foundHashes = array();
414 // Calculate new nonce
415 $nonce = calculateNonce($nonce);
417 // Add reward to total
418 $totalReward += $reward;
420 // Calculate average block value
421 $blockValue = $totalReward / $totalBlocks * $totalHashes / (BLOCK_SIZE * $totalBlocks);
423 // Calculate reward per hour (= 3600 seconds)
424 $rewardPerHour = $totalReward / abs(microtime(TRUE) - START_TIME) * 3600;
426 print ('totalReward=' . $totalReward . ',blockValue=' . $blockValue . ',rewardPerHour=' . $rewardPerHour . PHP_EOL);