2 error_reporting(E_ALL | E_STRICT);
4 define('HASH_ALGO', MHASH_RIPEMD320);
5 define('BLOCK_SIZE', 1000);
6 define('NONCE_INCREMENT', 1.0);
7 define('START_TIME', microtime(TRUE));
12 * @author Roland Haeder <roland@mxchange.org>
13 * @copyright Copyright (c) 2013 by Core Developer Team
14 * @license See LICENSE (public-domain)
18 * Calculates a simple but stronger hash from given string. No salts are being
21 * @param $str The string to be hashed
22 * @return $hash The hash from string $str
24 function hashString ($str) {
25 // Calculate strong hash from given string
26 $hash = mhash(HASH_ALGO, $str);
28 // Return it hexadecimal-encoded
29 return bin2hex($hash);
33 * Double-hashes given string. This is done by hashing the given string and
34 * then hashing the generated hash again.
36 * @param $str The string to be hashed 4 times
37 * @return $hash The generated hash
39 function doubleHashString ($str) {
40 // Generate hash from given hash
41 $hash = hashString(hashString($str));
48 * Calculates a "modula-hash" based given two hashes.
50 * @param $hash1 Hash 1
51 * @param $hash2 Hash 2
53 function modulaHash ($hash1, $hash2) {
54 // Both must have same length
55 assert(strlen($hash1) === strlen($hash2));
60 // "Walk" trough first hash and get every 2 byte of both hashes
61 for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
65 // Get both hash parts and convert to ASCII number
66 $part1 = hexdec(substr($hash1, $idx, 2));
67 $part2 = hexdec(substr($hash2, $idx, 2));
70 * If part1 is larget part2, part1 is divident and vise-versa. But don't do it
73 if (($part1 > $part2) && ($part2 > 0)) {
74 // 'part1' is larger than 'part2'
75 $mod = $part1 % $part2;
76 } elseif (($part1 < $part2) && ($part1 > 0)) {
77 // 'part2' is larger than 'part1'
78 $mod = $part2 % $part1;
81 // "Invert" the result against 255
84 // Encode to hex, pre-pad it with zeros and add to new hash
85 $modulaHash .= padHex($mod);
88 // Modula hash must have same length as input hash
89 assert(strlen($modulaHash) === strlen($hash1));
96 * Calculates a "sqrt-hash" based given two hashes and single-hash it
98 * @param $hash1 Hash 1
99 * @param $hash2 Hash 2
101 function sqrtHash ($hash1, $hash2) {
102 // Both must have same length
103 assert(strlen($hash1) === strlen($hash2));
108 // "Walk" trough first hash and get every 2 byte of both hashes
109 for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
113 // Get both hash parts and convert to ASCII number
114 $part1 = hexdec(substr($hash1, $idx, 2));
115 $part2 = hexdec(substr($hash2, $idx, 2));
117 // Calculate square root of both parts being multiplied and round up, then "invert" it against 255
118 $sqrt = intval(255 - ceil(sqrt($part1 * $part2)));
120 // Encode to hex, pre-pad it with zeros and add to new hash
121 $sqrtHash .= padHex($sqrt);
124 // "sqrt-hash" must have same length as input hash
125 assert(strlen($sqrtHash) === strlen($hash1));
127 // Hash reversed "sqrt-hash" again and return it
128 return hashString(strrev($sqrtHash));
132 * Converts a number between 0 and 255 into a zero-padded hexadecimal string
134 * @param $num Number between 0 and 255
135 * @return $hex Hexadecimal string, padded with zeros
137 function padHex ($num) {
138 // Must be a integer number and between 0 and 255
139 assert(is_int($num));
144 $hex = str_pad(dechex($num), 2, '0', STR_PAD_LEFT);
151 * Calculates sum from given hash
153 * @param $hash Hash to calculate sum from
154 * @return $sum Sum from given hash
156 function calculateSumFromHash ($hash) {
157 // Everything starts with zero ...
161 for ($idx = 0; $idx < (strlen($hash) / 2); $idx++) {
163 $sum = $sum + (hexdec(substr($hash, $idx, 2)) * $idx & 256);
171 * Calculates new nonce
173 * @param $nonce Old nonce to be used
174 * @return $newNonce New nonce
176 function calculateNonce ($nonce) {
177 // Linear incrementation
178 $newNonce = $nonce + NONCE_INCREMENT;
185 * Calculates current block
187 * @return $blockSize Block size
188 * @todo This needs improvement
190 function getBlockSize () {
191 // For now only a constant block size
196 * Calculate "genesis" hashes, please note that these "genesis strings" are now
197 * known to the public as you can read them here in source code and therefore I
198 * will not use them for the real genesis hashes.
201 // A famous quote from Deus Ex 2 - Invisible War
202 doublehashString('"Informations must be free." - AI Helios from Deus Ex'),
203 // My name + URL of my first StatusNet instance
204 doubleHashString('Roland Haeder, https://status.mxchange.org'),
205 // A famous quote from Linus Torwalds
206 doubleHashString('"Software is like sex. Its better when its free." - Linus Torwalds'),
207 // Possible truth ;-)
208 doubleHashString('September 11 is a big lie.'),
211 doubleHashString('GNU is Not Uni*.'),
212 // WINE is not an emulator
213 doubleHashString('WINE Is Not an Emulator.'),
214 // FlightGear - Fly free!
215 doubleHashString('FlightGear - Fly free!'),
216 // Linus Torwalds Quote
217 doubleHashString('Your code is shit.. your argument is shit.'),
220 // Calculate "modula hash" from 1st/4th and 2nd/3rd
221 $modulaHashes = array(
223 modulaHash($hashes[0], $hashes[3]),
224 modulaHash($hashes[1], $hashes[2]),
227 modulaHash($hashes[4], $hashes[7]),
228 modulaHash($hashes[5], $hashes[6]),
231 // Calculate "sqrt hash"
233 sqrtHash($modulaHashes[0], $modulaHashes[1]),
234 sqrtHash($modulaHashes[2], $modulaHashes[3])
237 // Calulcate modula hash
238 $modulaHash = doubleHashString(modulaHash($sqrtHashes[0], $sqrtHashes[1]));
241 print ('hashes=' . print_r($hashes, TRUE));
242 print ('modulaHashes=' . print_r($modulaHashes, TRUE));
243 print ('sqrtHashes=' . print_r($sqrtHashes, TRUE));
244 print ('modulaHash=' . $modulaHash . PHP_EOL);
246 // Total reward + hashes
251 // Create nonce (small)
252 $nonce = 1 / mt_rand();
255 // Init hash-per-block counter and hashrate
259 // Wait for BLOCK_SIZE iterations (= found hashes). This is one block
260 $timeBlock = microtime(TRUE);
261 $timeDisplay = $timeBlock;
263 // Time waited for a good block again (no iteration)
266 while ($hashesPerBlock <= getBlockSize()) {
270 // Create hash from modulaHash ("genesis hash") and nonce
271 $nonceHash = doubleHashString($modulaHash . $nonce);
274 $sumNonce = calculateSumFromHash($nonceHash);
275 $sumModula = calculateSumFromHash($modulaHash);
277 // Now start the "mining" ...
278 $timeHash = microtime(TRUE);
279 while ($sumNonce <= $sumModula) {
281 $sumNonce = calculateSumFromHash($nonceHash);
282 $sumModula = calculateSumFromHash($modulaHash);
284 // Calculate new nonce
285 $nonce = calculateNonce($nonce);
288 $nonceHash = doubleHashString($modulaHash . $nonce);
292 //print ('nonce=' . $nonce . ',iter=' . $iter . PHP_EOL);
293 //print ('nonceHash=' . $nonceHash . PHP_EOL);
294 //print ('sumNonce=' . $sumNonce . PHP_EOL);
295 //print ('sumModula=' . $sumModula . PHP_EOL);
298 // If the iteration is zero, then no hash is found
301 $timeBadHashes += abs(microtime(TRUE) - $timeHash);
303 // Nothing found, so calculate new nonce
304 $nonce = calculateNonce($nonce);
310 // Add amount of hashes to block (double-hash)
311 $hashesPerBlock += $iter * 2 + 2;
313 // Time spend in loop
314 $testTime = abs(microtime(TRUE) - $timeDisplay);
317 if ($testTime >= 1) {
318 // Calculate hashrate/sec
319 $timeHash = abs(microtime(TRUE) - $timeHash);
320 $hashrate = 1 / $timeHash * $iter * 2 + 2;
321 print ('hashesPerBlock=' . $hashesPerBlock . ',hashrate=' . $hashrate . ' hashes/sec.' . PHP_EOL);
324 $timeDisplay = microtime(TRUE);
328 //print ('nonceHash=' . $nonceHash .',iter=' . $iter . PHP_EOL);
331 // Time taken for one block
332 $timeBlock = abs(microtime(TRUE) - $timeBlock);
333 //print ('calculateSumFromHash(modulaHash)=' . calculateSumFromHash($modulaHash) . PHP_EOL);
334 //print ('calculateSumFromHash(nonceHash)=' . calculateSumFromHash($nonceHash) . PHP_EOL);
336 // Is the hash rate unset?
337 if ($hashrate == 0) {
338 // Then calculate it again
339 $hashrate = 1 / $timeBlock * $iter * 2 + 2;
343 $reward = abs($timeBlock - $timeBadHashes) / $hashrate * $hashesPerBlock / getBlockSize() * 1000;
344 print ('timeBlock=' . $timeBlock . ',timeBadHashes=' . $timeBadHashes . ',hashesPerBlock=' . $hashesPerBlock .',reward=' . $reward . PHP_EOL);
347 $totalHashes += $hashesPerBlock;
351 // Use nonceHash as next modula hash
352 $modulaHash = $nonceHash;
354 // Add reward to total
355 $totalReward += $reward;
357 // Calculate average block value
358 $blockValue = $totalReward / $totalBlocks * $totalHashes / (getBlockSize() * $totalBlocks);
360 // Calculate reward per hour (= 3600 seconds)
361 $rewardPerHour = $totalReward / abs(microtime(TRUE) - START_TIME) * 3600;
363 print ('totalReward=' . $totalReward . ',blockValue=' . $blockValue . ',rewardPerHour=' . $rewardPerHour . PHP_EOL);