eb55f6c00c0b5c8953618495f80047dca5ef5965
[core.git] / contrib / chash / chash.php
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3
4 define('HASH_ALGO', MHASH_RIPEMD320);
5 define('BLOCK_SIZE', 100);
6 define('NONCE_INCREMENT', 0.0000000001);
7 define('START_TIME', microtime(TRUE));
8
9 // Found hashes
10 $foundHashes = array();
11
12 /**
13  * Continued-hashing
14  *
15  * @author              Roland Haeder <roland@mxchange.org>
16  * @copyright   Copyright (c) 2013 by Core Developer Team
17  * @license             See LICENSE (public-domain)
18  */
19
20 /**
21  * Calculates a simple but stronger hash from given string. No salts are being
22  * added here.
23  *
24  * @param       $str    The string to be hashed
25  * @return      $hash   The hash from string $str
26  */
27 function hashString ($str) {
28         // Calculate strong hash from given string
29         $hash = mhash(HASH_ALGO, $str);
30
31         // Return it hexadecimal-encoded
32         return bin2hex($hash);
33 }
34
35 /**
36  * Double-hashes given string. This is done by hashing the given string and
37  * then hashing the generated hash again.
38  *
39  * @param       $str    The string to be hashed 4 times
40  * @return      $hash   The generated hash
41  */
42 function doubleHashString ($str) {
43         // Generate hash from given hash
44         $hash = hashString(hashString($str));
45
46         // Return it
47         return $hash;
48 }
49
50 /**
51  * Calculates a "modula-hash" based given two hashes.
52  *
53  * @param       $hash1  Hash 1
54  * @param       $hash2  Hash 2
55  */
56 function modulaHash ($hash1, $hash2) {
57         // Both must have same length
58         assert(strlen($hash1) === strlen($hash2));
59
60         // Init new hash
61         $modulaHash = '';
62
63         // "Walk" trough first hash and get every 2 byte of both hashes
64         for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
65                 // Init modula value
66                 $mod = 0;
67
68                 // Get both hash parts and convert to ASCII number
69                 $part1 = hexdec(substr($hash1, $idx, 2));
70                 $part2 = hexdec(substr($hash2, $idx, 2));
71
72                 /*
73                  * If part1 is larget part2, part1 is divident and vise-versa. But don't do it
74                  * if one is zero
75                  */
76                 if (($part1 > $part2) && ($part2 > 0)) {
77                         // 'part1' is larger than 'part2'
78                         $mod = $part1 % $part2;
79                 } elseif (($part1 < $part2) && ($part1 > 0)) {
80                         // 'part2' is larger than 'part1'
81                         $mod = $part2 % $part1;
82                 }
83
84                 // "Invert" the result against 255
85                 $mod = 255 - $mod;
86
87                 // Encode to hex, pre-pad it with zeros and add to new hash
88                 $modulaHash .= padHex($mod);
89         } // END - for
90
91         // Modula hash must have same length as input hash
92         assert(strlen($modulaHash) === strlen($hash1));
93
94         // Return modula hash
95         return $modulaHash;
96 }
97
98 /**
99  * Calculates a "sqrt-hash" based given two hashes and single-hash it
100  *
101  * @param       $hash1  Hash 1
102  * @param       $hash2  Hash 2
103  */
104 function sqrtHash ($hash1, $hash2) {
105         // Both must have same length
106         assert(strlen($hash1) === strlen($hash2));
107
108         // Init new hash
109         $sqrtHash = '';
110
111         // "Walk" trough first hash and get every 2 byte of both hashes
112         for ($idx = 0; $idx < strlen($hash1); $idx += 2) {
113                 // Init modula value
114                 $mod = 0;
115
116                 // Get both hash parts and convert to ASCII number
117                 $part1 = hexdec(substr($hash1, $idx, 2));
118                 $part2 = hexdec(substr($hash2, $idx, 2));
119
120                 // Calculate square root of both parts being multiplied and round up, then "invert" it against 255
121                 $sqrt = intval(255 - ceil(sqrt($part1 * $part2)));
122
123                 // Encode to hex, pre-pad it with zeros and add to new hash
124                 $sqrtHash .= padHex($sqrt);
125         } // END - for
126
127         // "sqrt-hash" must have same length as input hash
128         assert(strlen($sqrtHash) === strlen($hash1));
129
130         // Hash reversed "sqrt-hash" again and return it
131         return hashString(strrev($sqrtHash));
132 }
133
134 /**
135  * Converts a number between 0 and 255 into a zero-padded hexadecimal string
136  *
137  * @param       $num    Number between 0 and 255
138  * @return      $hex    Hexadecimal string, padded with zeros
139  */
140 function padHex ($num) {
141         // Must be a integer number and between 0 and 255
142         assert(is_int($num));
143         assert($num >= 0);
144         assert($num <= 255);
145
146         // Convert it
147         $hex = str_pad(dechex($num), 2, '0', STR_PAD_LEFT);
148
149         // ... and return it
150         return $hex;
151 }
152
153 /**
154  * Calculates sum from given hash
155  *
156  * @param       $hash   Hash to calculate sum from
157  * @return      $sum    Sum from given hash
158  */
159 function calculateSumFromHash ($hash) {
160         // Everything starts with zero ...
161         $sum = 0;
162
163         // Loop through hash
164         for ($idx = 0; $idx < (strlen($hash) / 2); $idx++) {
165                 // And add it
166                 $sum = $sum + (hexdec(substr($hash, $idx, 2)) * $idx & 256);
167         } // END - for
168
169         // And return it
170         return $sum;
171 }
172
173 /**
174  * Calculates new nonce
175  *
176  * @param       $nonce          Old nonce to be used
177  * @return      $newNonce       New nonce
178  */
179 function calculateNonce ($nonce) {
180         // Linear incrementation
181         $newNonce = $nonce + NONCE_INCREMENT;
182
183         // Return new value
184         return $newNonce;
185 }
186
187 /*
188  * Calculate "genesis" hashes, please note that these "genesis strings" are now
189  * known to the public as you can read them here in source code and therefore I
190  * will not use them for the real genesis hashes.
191  */
192 $hashes = array(
193         // A famous quote from Deus Ex 2 - Invisible War
194         doublehashString('"Informations must be free." - AI Helios from Deus Ex'),
195         // My name + URL of my first StatusNet instance
196         doubleHashString('Roland Haeder, https://status.mxchange.org'),
197         // A famous quote from Linus Torwalds
198         doubleHashString('"Software is like sex. Its better when its free." - Linus Torwalds'),
199         // Possible truth ;-)
200         doubleHashString('September 11 is a big lie.'),
201
202         // GNU is not Uni*
203         doubleHashString('GNU is Not Uni*.'),
204         // WINE is not an emulator
205         doubleHashString('WINE Is Not an Emulator.'),
206         // FlightGear - Fly free!
207         doubleHashString('FlightGear - Fly free!'),
208         // Linus Torwalds Quote
209         doubleHashString('Your code is shit.. your argument is shit.'),
210 );
211
212 // Calculate "modula hash" from 1st/4th and 2nd/3rd
213 $modulaHashes = array(
214         // "Block" 0
215         modulaHash($hashes[0], $hashes[3]),
216         modulaHash($hashes[1], $hashes[2]),
217
218         // "Block" 1
219         modulaHash($hashes[4], $hashes[7]),
220         modulaHash($hashes[5], $hashes[6]),
221 );
222
223 // Calculate "sqrt hash"
224 $sqrtHashes = array(
225         sqrtHash($modulaHashes[0], $modulaHashes[1]),
226         sqrtHash($modulaHashes[2], $modulaHashes[3])
227 );
228
229 // Calulcate modula hash
230 $modulaHash = doubleHashString(modulaHash($sqrtHashes[0], $sqrtHashes[1]));
231
232 // Output results
233 print ('hashes=' . print_r($hashes, TRUE));
234 print ('modulaHashes=' . print_r($modulaHashes, TRUE));
235 print ('sqrtHashes=' . print_r($sqrtHashes, TRUE));
236 print ('modulaHash=' . $modulaHash . PHP_EOL);
237
238 // Total reward + hashes
239 $totalReward = 0;
240 $totalHashes = 0;
241 $totalBlocks = 0;
242
243 // Create nonce (small)
244 $nonce = 1 / mt_rand();
245
246 while (TRUE) {
247         // Init hash-per-block counter and hashrate
248         $hashesPerBlock = 0;
249         $hashrate = 0;
250
251         // Wait for BLOCK_SIZE iterations (= found hashes). This is one block
252         $timeBlock = microtime(TRUE);
253         $timeDisplay = $timeBlock;
254
255         // Time waited for a good block again (no iteration)
256         $timeBadHashes = 0;
257
258         while (count($foundHashes) <= BLOCK_SIZE) {
259                 // Create hash from modulaHash ("genesis hash") and nonce
260                 $nonceHash = doubleHashString($modulaHash . $nonce);
261
262                 // Calculate sums
263                 $sumNonce  = calculateSumFromHash($nonceHash);
264                 $sumModula = calculateSumFromHash($modulaHash);
265
266                 // Init counter
267                 $iter = 0;
268                 $iterSecond = 0;
269
270                 // Now start the "mining" ...
271                 $timeHash = microtime(TRUE);
272                 while ($sumNonce >= $sumModula) {
273                         // Calculate new nonce
274                         $nonce = calculateNonce($nonce);
275
276                         // And hash again
277                         $nonceHash = doubleHashString($modulaHash . $nonce);
278
279                         // Calculate sums
280                         $sumNonce  = calculateSumFromHash($nonceHash);
281
282                         // Time spend in loop
283                         $testTime = abs(microtime(TRUE) - $timeDisplay);
284
285                         // Calculate hashrate/sec
286                         $hashrate = 1 / $testTime * $iterSecond * 2;
287
288                         // Only every second
289                         if ($testTime >= 1) {
290                                 // Display hash rate
291                                 print ('hashrate=' . $hashrate . ' hashes/sec,iterSecond=' . $iterSecond . ' iterations/sec' . PHP_EOL);
292
293                                 // Reset timer
294                                 $timeDisplay = microtime(TRUE);
295                                 $iterSecond  = 0;
296                         } // END - if
297
298                         // Next round
299                         $iter++;
300                         $iterSecond++;
301                         //print ('nonce=' . $nonce . ',iter=' . $iter . PHP_EOL);
302                         //print ('nonceHash=' . $nonceHash . PHP_EOL);
303                         //print ('sumNonce=' . $sumNonce . PHP_EOL);
304                         //print ('sumModula=' . $sumModula . PHP_EOL);
305                 } // END - while
306
307                 // If the iteration is zero, then no hash is found
308                 if ($iter == 0) {
309                         // Bad hash found
310                         $timeBadHashes += abs(microtime(TRUE) - $timeHash);
311
312                         // And next round
313                         //print('BAD:nonce=' . $nonce . PHP_EOL);
314
315                         // Nothing found, so calculate new nonce
316                         $nonce = calculateNonce($nonce);
317                         continue;
318                 } // END - if
319
320                 // Add amount of hashes per block (double-hash)
321                 $hashesPerBlock += $iter * 2 + 2;
322                 array_push($foundHashes, $nonceHash);
323
324                 // Found hash:
325                 print ('FOUND: nonceHash=' . $nonceHash .',iter=' . $iter . PHP_EOL);
326
327                 // Use nonceHash as next modula hash
328                 $modulaHash = $nonceHash;
329         } // END - while
330
331         // Time taken for one block
332         $timeBlock = abs(microtime(TRUE) - $timeBlock);
333
334         // Calculate reward
335         $reward = abs($timeBlock - $timeBadHashes) / $hashrate * $hashesPerBlock / BLOCK_SIZE * 1000;
336         print ('timeBlock=' . $timeBlock . ',timeBadHashes=' . $timeBadHashes . ',hashesPerBlock=' . $hashesPerBlock .',reward=' . $reward . PHP_EOL);
337
338         // Block completed
339         $totalHashes += $hashesPerBlock;
340         $totalBlocks++;
341         $hashesPerBlock = 0;
342         $foundHashes = array();
343
344         // Calculate new nonce
345         $nonce = calculateNonce($nonce);
346
347         // Add reward to total
348         $totalReward += $reward;
349
350         // Calculate average block value
351         $blockValue = $totalReward / $totalBlocks * $totalHashes / (BLOCK_SIZE * $totalBlocks);
352
353         // Calculate reward per hour (= 3600 seconds)
354         $rewardPerHour = $totalReward / abs(microtime(TRUE) - START_TIME) * 3600;
355
356         print ('totalReward=' . $totalReward . ',blockValue=' . $blockValue . ',rewardPerHour=' . $rewardPerHour . PHP_EOL);
357 } // END - while
358
359 // [EOF]
360 ?>