├── example.php
├── readme.md
└── xpgen.php
/example.php:
--------------------------------------------------------------------------------
1 | 204455-473963-727110-378854-169136-901266-745572
13 |
14 | Error codes:
15 | 0 is success
16 | ERR_TOO_SHORT = 1
17 | ERR_TOO_LARGE = 2
18 | ERR_INVALID_CHARACTER = 3
19 | ERR_INVALID_CHECK_DIGIT = 4
20 | ERR_UNKNOWN_VERSION = 5
21 | ERR_UNLUCKY = 6;
22 |
23 | */
24 |
25 | include_once 'xpgen.php';
26 |
27 | $in = $_GET["key"];
28 |
29 | $out = "";
30 | $result = generate($in, $out);
31 |
32 | if($result==0) {
33 | echo("OK
result: $out");
34 | die();
35 | } else {
36 | echo("Failed
error code: $result");
37 | }
38 | die();
39 | ?>
40 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # xpactivate32_php
2 | PHP port of xp_activate32.exe
3 |
4 | This is a full PHP port of xp_activate32.exe. Ported line by line. But why? - because why not! And to be honest, I don't understand any of the calculations, code was made in a way to replicate the original code workings in 1:1.
5 |
6 | Since it's a "1:1 port", before submitting a issue with an installation id that doesn't work, check if it works in the original xp\_activate32.exe. If it doesn't work in this port, but works with xp\_activate32.exe - then go ahead.
7 |
8 | Source used: https://archive.org/details/xp_activate32_src
9 |
10 | # Usage
11 | xpgen.php is the main file.
12 | ```php
13 | $out = "";
14 | $input = "070846-984606-199354-110900-862045-444713-121295-109842-549701";
15 | $result = generate($input, $out); // Result code will be stored to $result and generated activation id to $out
16 |
17 | // $out -> 204455-473963-727110-378854-169136-901266-745572
18 | ```
19 |
20 | ## Error codes:
21 | ```
22 | SUCCESS = 0
23 | ERR_TOO_SHORT = 1
24 | ERR_TOO_LARGE = 2
25 | ERR_INVALID_CHARACTER = 3
26 | ERR_INVALID_CHECK_DIGIT = 4
27 | ERR_UNKNOWN_VERSION = 5
28 | ERR_UNLUCKY = 6;
29 | ```
30 |
31 | # Live demo
32 | A working live demo of this port with a simple frontend is available [here](https://maniek86.xyz/dev/xpgen/xpgen.html).
33 |
--------------------------------------------------------------------------------
/xpgen.php:
--------------------------------------------------------------------------------
1 | = 0) {
70 | return gmp_sub($in, gmp_mul($max_int64, gmp_init(2)));
71 | }
72 | // Handle underflow
73 | elseif (gmp_cmp($in, $min_int64) < 0) {
74 | return gmp_add($in, gmp_mul($max_int64, gmp_init(2)));
75 | }
76 | return $in;
77 | }
78 |
79 | function uint8($in) {
80 | global $max_uint8;
81 |
82 | $out = gmp_mod($in, $max_uint8);
83 |
84 | // underflow
85 | if (gmp_cmp($out, gmp_init(0)) < 0) {
86 | $out = gmp_add($out, $max_uint8);
87 | }
88 |
89 |
90 | return $out;
91 | }
92 |
93 | function uint16($in) {
94 | global $max_uint16;
95 |
96 | $out = gmp_mod($in, $max_uint16);
97 |
98 | // underflow
99 | if (gmp_cmp($out, gmp_init(0)) < 0) {
100 | $out = gmp_add($out, $max_uint16);
101 | }
102 |
103 |
104 | return $out;
105 | }
106 |
107 |
108 | function residue_add($x, $y) {
109 | global $MOD;
110 |
111 | $z = uint64(gmp_add($x, $y));
112 |
113 | if(gmp_cmp($z, $MOD)>=0) {
114 | $z = uint64(gmp_sub($z, $MOD));
115 | }
116 |
117 | return $z;
118 | }
119 |
120 | function residue_sub($x, $y) {
121 | global $MOD;
122 |
123 | $z = uint64(gmp_sub($x, $y));
124 |
125 | if(gmp_cmp($x, $y)<0) {
126 | $z = uint64(gmp_add($z, $MOD));
127 | }
128 |
129 | return $z;
130 | }
131 |
132 | function __emulu($x, $y) {
133 | return uint64(gmp_mul($x,$y));
134 | }
135 |
136 | function __umul128($multiplier, $multiplicand, &$product_hi) {
137 | // multiplier = ab = a * 2^32 + b
138 | // multiplicand = cd = c * 2^32 + d
139 | // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
140 | $a = uint64(gmp_shiftr($multiplier, 32));
141 |
142 | $b = uint32($multiplier);
143 | $c = uint64(gmp_shiftr($multiplicand,32));
144 | $d = uint32($multiplicand);
145 |
146 | $ad = __emulu($a, $d);
147 | $bd = __emulu($b, $d);
148 |
149 | $adbc = uint64(gmp_add($ad,__emulu($b , $c)));
150 |
151 | if(gmp_cmp($adbc, $ad) < 0) {
152 | $adbc_carry = 1;
153 | } else {
154 | $adbc_carry = 0;
155 | }
156 |
157 | // multiplier * multiplicand = product_hi * 2^64 + product_lo
158 | $product_lo = uint64(gmp_add($bd,uint64(gmp_shiftl($adbc, 32))));
159 |
160 | if(gmp_cmp($product_lo, $bd) < 0) {
161 | $product_lo_carry = 1;
162 | } else {
163 | $product_lo_carry = 0;
164 | }
165 |
166 | $product_hi = uint64(gmp_add(uint64(gmp_add(uint64(gmp_add(__emulu($a , $c),uint64(gmp_shiftr($adbc, 32)))), uint64(gmp_shiftl($adbc_carry, 32)))), $product_lo_carry));
167 |
168 | return $product_lo;
169 | }
170 |
171 | function ui128_quotient_mod($lo, $hi) {
172 | // hi:lo * ceil(2**170/MOD) >> (64 + 64 + 42)
173 | $prod1 = gmp_init(0);
174 | __umul128($lo, gmp_init("0x604fa6a1c6346a87"), $prod1);
175 | $part1hi = gmp_init(0);
176 | $part1lo = __umul128($lo, gmp_init("0x2d351c6d04f8b"), $part1hi);
177 | $part2hi = gmp_init(0);
178 | $part2lo = __umul128($hi, gmp_init("0x604fa6a1c6346a87"), $part2hi);
179 | $sum1 = uint64(gmp_add($part1lo, $part2lo));
180 |
181 | $sum1carry = 0;
182 |
183 | if(gmp_cmp($sum1, $part1lo) < 0) {
184 | $sum1carry = 1;
185 | }
186 |
187 | $sum1 = uint64(gmp_add($sum1,$prod1));
188 |
189 | if(gmp_cmp($sum1, $prod1) < 0) {
190 | $sum1carry = $sum1carry + 1;
191 | }
192 |
193 | $sum1carry = gmp_init($sum1carry);
194 |
195 | $prod2 = uint64(gmp_add($part1hi, uint64(gmp_add($part2hi, $sum1carry))));
196 | $prod3hi = 0;
197 | $prod3lo = __umul128($hi, gmp_init("0x2d351c6d04f8b"), $prod3hi);
198 | $prod3lo = uint64(gmp_add($prod3lo, $prod2));
199 | if(gmp_cmp($prod3lo, $prod2) < 0) {
200 | $prod3hi = uint64(gmp_add($prod3hi, 1));
201 | }
202 |
203 | return uint64(gmp_or(uint64(gmp_shiftr($prod3lo, 42)),uint64(gmp_shiftl($prod3hi, 22))));
204 | }
205 |
206 | function residue_mul($x, $y) { // there is a bug
207 | global $MOD;
208 | // * ceil(2**170/MOD) = 0x2d351 c6d04f8b|604fa6a1 c6346a87 for (p-1)*(p-1) max
209 | $hi = gmp_init(0);
210 | $lo = __umul128($x, $y, $hi);
211 | $quotient = ui128_quotient_mod($lo,$hi);
212 | return uint64(gmp_sub($lo, uint64(gmp_mul($quotient, $MOD))));
213 | }
214 |
215 | function residue_pow($x, $y) {
216 | if(gmp_cmp($y,0)==0) {
217 | return gmp_init(1);
218 | }
219 |
220 | $cur = $x;
221 |
222 | while(! (gmp_cmp(gmp_and($y,1),0)>0)) { //while (!(y & 1)) {
223 | $cur = residue_mul($cur, $cur);
224 | $y = uint64(gmp_shiftr($y, 1));
225 | }
226 | $res = $cur;
227 |
228 | while (gmp_cmp($y,0)!=0) { // while ((y >>= 1) != 0) {
229 | $y = uint64(gmp_shiftr($y, 1));
230 |
231 | $cur = residue_mul($cur, $cur);
232 |
233 | if(gmp_cmp(gmp_and($y, 1),0)>0) {
234 | $res = residue_mul($res, $cur);
235 | }
236 | }
237 |
238 | $y = uint64(gmp_shiftr($y, 1));
239 | return $res;
240 | }
241 |
242 | function inverse($u, $v) {
243 | $tmp = 0; // i64
244 | $xu = 1; // i64
245 | $xv = 0; // i64
246 | $v0 = $v;
247 | while (gmp_cmp($u,1)>0) {
248 | //ui64 d = v / u; ui64 remainder = v % u;
249 | $d = uint64(gmp_div($v,$u));
250 | $remainder = uint64(gmp_mod($v, $u));
251 | $tmp = int64($u);
252 | $u = $remainder;
253 | $v = uint64($tmp);
254 | $tmp = $xu;
255 | $xu = int64(gmp_sub($xv,gmp_mul($d, $xu)));
256 | $xv = int64($tmp);
257 | }
258 | //xu += (xu < 0 ? v0 : 0);
259 | if(gmp_cmp($xu,0)<0) {
260 | $xu = int64(gmp_add($xu,$v0));
261 | }
262 | return uint64($xu);
263 | }
264 |
265 | function residue_inv($x) {
266 | global $MOD;
267 | return inverse($x, $MOD);
268 | }
269 |
270 | // #define BAD 0xFFFFFFFFFFFFFFFFull
271 | // #define NON_RESIDUE 43
272 | $BAD = gmp_init("0xFFFFFFFFFFFFFFFF");
273 | $NON_RESIDUE = gmp_init("43");
274 |
275 | function residue_sqrt($what) {
276 | global $BAD, $MOD, $NON_RESIDUE, $debugEN;
277 | // if(!what) - if zero
278 | if (gmp_cmp($what,0)==0)
279 | return gmp_init(0);
280 |
281 | $g = $NON_RESIDUE;
282 | $z = gmp_init(0);
283 | $y = $z;
284 | $r = $z;
285 | $x = $z;
286 | $b = $z;
287 | $t = $z;
288 |
289 | $e = $z;
290 | $q = uint64(gmp_sub($MOD,1));
291 | //while (!(q & 1))
292 | // e++, q >>= 1;
293 |
294 | while (! (gmp_cmp(gmp_and($q, 1),0)>0)) {
295 | $e = uint64(gmp_add($e, 1));
296 | $q = uint64(gmp_shiftr($q, 1));
297 | }
298 |
299 | $z = residue_pow($g, $q);
300 | $y = $z;
301 | $r = $e;
302 | $x = residue_pow($what, uint64(gmp_div(uint64(gmp_sub($q,1)),2))); // (q - 1) / 2
303 | $b = residue_mul(residue_mul($what, $x), $x);
304 | $x = residue_mul($what, $x);
305 |
306 | while (gmp_cmp($b,1)!=0) {
307 | $m = gmp_init(0);
308 | $b2 = $b;
309 | do {
310 | $m = uint64(gmp_add($m,1));
311 | $b2 = residue_mul($b2, $b2);
312 | } while (gmp_cmp($b2,1)!=0);
313 | if (gmp_cmp($m, $r)==0)
314 | return $BAD;
315 | $t = residue_pow($y, uint64(gmp_shiftl(1, uint64(gmp_sub(uint64(gmp_sub($r, $m)), 1)))));
316 | $y = residue_mul($t, $t);
317 | $r = $m;
318 | $x = residue_mul($x, $t);
319 | $b = residue_mul($b, $y);
320 | }
321 | if (gmp_cmp(residue_mul($x, $x),$what)!=0) {
322 | //printf("internal error in sqrt\n");
323 | return $BAD;
324 | }
325 | return $x;
326 | }
327 |
328 | /*
329 | typedef struct {
330 | ui64 u[2];
331 | ui64 v[2];
332 | } TDivisor;
333 | */
334 |
335 | class TDivisor {
336 | public $u;
337 | public $v;
338 | }
339 |
340 | $f = Array(gmp_init(0), gmp_init("0x21840136C85381"),gmp_init("0x44197B83892AD0"),gmp_init("0x1400606322B3B04"),gmp_init("0x1400606322B3B04"),gmp_init("1"));
341 |
342 | function find_divisor_v(&$d) { // int find_divisor_v(TDivisor* d), u[] input v[] output
343 | global $f, $BAD;
344 | // u | v^2 - f
345 | // u = u0 + u1*x + x^2
346 | // f%u = f0 + f1*x
347 | $v1 = gmp_init(0);
348 | $f2 = Array(); //ui64 f2[6];
349 | //int i, j;
350 | $i = 0;
351 | $j = 0;
352 | for ($i = 0; $i < 6; $i++) {
353 | $f2[$i] = $f[$i];
354 | }
355 |
356 | $u0 = $d->u[0];
357 | $u1 = $d->u[1];
358 |
359 | for($j=3; $j>=0; $j--) {
360 | $f2[$j] = residue_sub($f2[$j], residue_mul($u0, $f2[$j + 2]));
361 | $f2[$j + 1] = residue_sub($f2[$j + 1], residue_mul($u1, $f2[$j + 2]));
362 | $f2[$j + 2] = 0;
363 | }
364 | // v = v0 + v1*x
365 | // u | (v0^2 - f0) + (2*v0*v1 - f1)*x + v1^2*x^2 = u0*v1^2 + u1*v1^2*x + v1^2*x^2
366 | // v0^2 - f0 = u0*v1^2
367 | // 2*v0*v1 - f1 = u1*v1^2
368 | // v0^2 = f0 + u0*v1^2 = (f1 + u1*v1^2)^2 / (2*v1)^2
369 | // (f1^2) + 2*(f1*u1-2*f0) * v1^2 + (u1^2-4*u0) * v1^4 = 0
370 | // v1^2 = ((2*f0-f1*u1) +- 2*sqrt(-f0*f1*u1 + f0^2 + f1^2*u0))) / (u1^2-4*u0)
371 | $f0 = $f2[0];
372 | $f1 = $f2[1];
373 | $u0double = residue_add($u0, $u0);
374 | $coeff2 = residue_sub(residue_mul($u1, $u1), residue_add($u0double, $u0double));
375 | $coeff1 = residue_sub(residue_add($f0, $f0), residue_mul($f1, $u1));
376 | if (gmp_cmp($coeff2, 0) == 0) {
377 | if (gmp_cmp($coeff1, 0) == 0) {
378 | if (gmp_cmp($f1, 0) == 0) {
379 | // impossible
380 | //printf("bad f(), double root detected\n");
381 | }
382 | return 0;
383 | }
384 | $sqr = residue_mul(residue_mul($f1, $f1), residue_inv(residue_add($coeff1, $coeff1)));
385 | $v1 = residue_sqrt($sqr);
386 | if (gmp_cmp($v1, $BAD) == 0)
387 | return 0;
388 | } else {
389 | $d = residue_add(residue_mul($f0, $f0), residue_mul($f1, residue_sub(residue_mul($f1, $u0), residue_mul($f0, $u1))));
390 | $d = residue_sqrt($d);
391 | if (gmp_cmp($d, $BAD) == 0)
392 | return 0;
393 | $d = residue_add($d, $d);
394 | $inv = residue_inv($coeff2);
395 | $root = residue_mul(residue_add($coeff1, $d), $inv);
396 | $v1 = residue_sqrt($root);
397 | if (gmp_cmp($v1, $BAD) == 0) {
398 | $root = residue_mul(residue_sub($coeff1, $d), $inv);
399 | $v1 = residue_sqrt($root);
400 | if (gmp_cmp($v1, $BAD) == 0)
401 | return 0;
402 | }
403 | }
404 | $v0 = residue_mul(residue_add($f1, residue_mul($u1, residue_mul($v1, $v1))), residue_inv(residue_add($v1, $v1)));
405 | $d->u[0] = $u0;
406 | $d->u[1] = $u1;
407 | $d->v[0] = $v0;
408 | $d->v[1] = $v1;
409 | return 1;
410 | }
411 |
412 | // UNTESTED
413 | function polynomial_mul($adeg, $a, $bdeg, $b, $resultprevdeg, &$result) { //static int polynomial_mul(int adeg, const ui64 a[], int bdeg, const ui64 b[], int resultprevdeg, ui64 result[])
414 | // $a[], $b[], $result[] is uint64
415 | if ($adeg < 0 || $bdeg < 0)
416 | return $resultprevdeg;
417 | // int i, j;
418 | $i = 0;
419 | $j = 0;
420 |
421 | for ($i = $resultprevdeg + 1; $i <= $adeg + $bdeg; $i++)
422 | $result[$i] = gmp_init(0);
423 | $resultprevdeg = $i - 1;
424 | for ($i = 0; $i <= $adeg; $i++)
425 | for ($j = 0; $j <= $bdeg; $j++)
426 | $result[$i + $j] = residue_add($result[$i + $j], residue_mul($a[$i], $b[$j]));
427 | while ($resultprevdeg >= 0 && gmp_cmp($result[$resultprevdeg],0) == 0)
428 | --$resultprevdeg;
429 | return $resultprevdeg;
430 | }
431 |
432 | // UNTESTED
433 | function polynomial_div_monic($adeg, &$a, $bdeg, $b, &$quotient) { //static int polynomial_div_monic(int adeg, ui64 a[], int bdeg, const ui64 b[], ui64* quotient)
434 | // $a[], $b[], $quotient are uint64
435 | //assert(bdeg >= 0);
436 | //assert(b[bdeg] == 1);
437 | //int i, j;
438 | //echo("bdeg: $bdeg\n");
439 | //debug_print_backtrace();
440 | $i = 0;
441 | $j = 0;
442 | for ($i = ($adeg - $bdeg); $i >= 0; $i--) {
443 | $q = $a[$i + $bdeg]; // uint64
444 | //if (gmp_cmp($quotient[0],0)>0)
445 | if(gettype($quotient)=="array")
446 | $quotient[$i] = $q;
447 | for ($j = 0; $j < $bdeg; $j++)
448 | $a[$i + $j] = residue_sub($a[$i + $j], residue_mul($q, $b[$j]));
449 | $a[$i + $j] = gmp_init(0);
450 | }
451 | $i += $bdeg;
452 | while ($i >= 0 && gmp_cmp($a[$i], 0) == 0)
453 | $i--;
454 | return $i;
455 | }
456 |
457 | // UNTESTED
458 | function polynomial_xgcd($adeg, $a, $bdeg, $b, &$pgcddeg, &$gcd, &$pmult1deg, &$mult1, &$pmult2deg, &$mult2) { //static void polynomial_xgcd(int adeg, const ui64 a[3], int bdeg, const ui64 b[3], int* pgcddeg, ui64 gcd[3], int* pmult1deg, ui64 mult1[3], int* pmult2deg, ui64 mult2[3])
459 | // $a[], $b[], $gcd[], $mult1[], $mult2[] are uint64
460 | $sdeg = -1;
461 | //ui64 s[3] = {0, 0, 0};
462 | $s = Array(gmp_init(0),gmp_init(0),gmp_init(0));
463 | $mult1deg = 0;
464 | $mult1[0] = gmp_init(1);
465 | $mult1[1] = gmp_init(0);
466 | $mult1[2] = gmp_init(0);
467 |
468 | $tdeg = 0;
469 | //ui64 t[3] = {1, 0, 0};
470 | $t = Array(gmp_init(1),gmp_init(0),gmp_init(0));
471 | $mult2deg = -1;
472 | $mult2[0] = gmp_init(0);
473 | $mult2[1] = gmp_init(0);
474 | $mult2[2] = gmp_init(0);
475 | $rdeg = $bdeg;
476 | //ui64 r[3] = {b[0], b[1], b[2]};
477 | $r = Array($b[0],$b[1],$b[2]);
478 | $gcddeg = $adeg;
479 | $gcd[0] = $a[0];
480 | $gcd[1] = $a[1];
481 | $gcd[2] = $a[2];
482 | // s*u1 + t*u2 = r
483 | // mult1*u1 + mult2*u2 = gcd
484 | while ($rdeg >= 0) {
485 | if ($rdeg > $gcddeg) {
486 | //unsigned tmp;
487 | $tmp = 0;
488 | //int tmpi;
489 | $tmpi = 0;
490 |
491 | $tmp = $rdeg; $rdeg = $gcddeg; $gcddeg = $tmp;
492 | $tmpi = $sdeg; $sdeg = $mult1deg; $mult1deg = $tmpi;
493 | $tmpi = $tdeg; $tdeg = $mult2deg; $mult2deg = $tmpi;
494 | //ui64 tmp2;
495 | $tmp2 = gmp_init(0);
496 | $tmp2 = $r[0]; $r[0] = $gcd[0]; $gcd[0] = $tmp2;
497 | $tmp2 = $r[1]; $r[1] = $gcd[1]; $gcd[1] = $tmp2;
498 | $tmp2 = $r[2]; $r[2] = $gcd[2]; $gcd[2] = $tmp2;
499 | $tmp2 = $s[0]; $s[0] = $mult1[0]; $mult1[0] = $tmp2;
500 | $tmp2 = $s[1]; $s[1] = $mult1[1]; $mult1[1] = $tmp2;
501 | $tmp2 = $s[2]; $s[2] = $mult1[2]; $mult1[2] = $tmp2;
502 | $tmp2 = $t[0]; $t[0] = $mult2[0]; $mult2[0] = $tmp2;
503 | $tmp2 = $t[1]; $t[1] = $mult2[1]; $mult2[1] = $tmp2;
504 | $tmp2 = $t[2]; $t[2] = $mult2[2]; $mult2[2] = $tmp2;
505 | continue;
506 | }
507 | //int delta = gcddeg - rdeg;
508 | $delta = $gcddeg - $rdeg;
509 | $mult = residue_mul($gcd[$gcddeg], residue_inv($r[$rdeg])); // ui64
510 | // quotient = mult * x**delta
511 | //assert(rdeg + delta < 3);
512 | for ($i = 0; $i <= $rdeg; $i++)
513 | $gcd[$i + $delta] = residue_sub($gcd[$i + $delta], residue_mul($mult, $r[$i]));
514 | while ($gcddeg >= 0 && gmp_cmp($gcd[$gcddeg], 0) == 0)
515 | $gcddeg--;
516 | //assert(sdeg + delta < 3);
517 | for ($i = 0; $i <= $sdeg; $i++)
518 | $mult1[$i + $delta] = residue_sub($mult1[$i + $delta], residue_mul($mult, $s[$i]));
519 | if ($mult1deg < $sdeg + $delta)
520 | $mult1deg = $sdeg + $delta;
521 | while ($mult1deg >= 0 && gmp_cmp($mult1[$mult1deg],0) == 0)
522 | $mult1deg--;
523 | //assert(tdeg + delta < 3);
524 | for ($i = 0; $i <= $tdeg; $i++)
525 | $mult2[$i + $delta] = residue_sub($mult2[$i + $delta], residue_mul($mult, $t[$i]));
526 | if ($mult2deg < $tdeg + $delta)
527 | $mult2deg = $tdeg + $delta;
528 | while ($mult2deg >= 0 && gmp_cmp($mult2[$mult2deg], 0) == 0)
529 | $mult2deg--;
530 | }
531 | // d1 = gcd, e1 = mult1, e2 = mult2
532 | $pgcddeg = $gcddeg;
533 | $pmult1deg = $mult1deg;
534 | $pmult2deg = $mult2deg;
535 | }
536 |
537 | // UNTESTED
538 | function u2poly(&$src, &$polyu, &$polyv) { //static int u2poly(const TDivisor* src, ui64 polyu[3], ui64 polyv[2])
539 | // $polyu[] and $polyv[] are uint64
540 | global $BAD;
541 |
542 | if (gmp_cmp($src->u[1], $BAD) != 0) {
543 | $polyu[0] = $src->u[0];
544 | $polyu[1] = $src->u[1];
545 | $polyu[2] = 1;
546 | $polyv[0] = $src->v[0];
547 | $polyv[1] = $src->v[1];
548 | return 2;
549 | }
550 | if (gmp_cmp($src->u[0], $BAD) != 0) {
551 | $polyu[0] = $src->u[0];
552 | $polyu[1] = 1;
553 | $polyv[0] = $src->v[0];
554 | $polyv[1] = 0;
555 | return 1;
556 | }
557 | $polyu[0] = gmp_init(1);
558 | $polyv[0] = gmp_init(0);
559 | $polyv[1] = gmp_init(0);
560 | return 0;
561 | }
562 |
563 | // UNTESTED
564 | function divisor_add($src1, $src2, &$dst) {// static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* dst)
565 | //ui64 u1[3], u2[3], v1[2], v2[2];
566 | global $f, $BAD;
567 | $gmp0 = gmp_init(0);
568 |
569 | $u1 = Array($gmp0,$gmp0,$gmp0);
570 | $u2 = Array($gmp0,$gmp0,$gmp0);
571 | $v1 = Array($gmp0,$gmp0);
572 | $v2 = Array($gmp0,$gmp0);
573 |
574 | $u1deg = u2poly($src1, $u1, $v1); // int
575 | $u2deg = u2poly($src2, $u2, $v2); // int
576 |
577 | //debug_print_backtrace();
578 |
579 |
580 | // extended gcd: d1 = gcd(u1, u2) = e1*u1 + e2*u2
581 | //int d1deg, e1deg, e2deg;
582 | $d1deg = 0;
583 | $e1deg = 0;
584 | $e2deg = 0;
585 | //ui64 d1[3], e1[3], e2[3];
586 | $d1 = Array($gmp0,$gmp0,$gmp0);
587 | $e1 = Array($gmp0,$gmp0,$gmp0);
588 | $e2 = Array($gmp0,$gmp0,$gmp0);
589 | polynomial_xgcd($u1deg, $u1, $u2deg, $u2, $d1deg, $d1, $e1deg, $e1, $e2deg, $e2);
590 |
591 | //assert(e1deg <= 1);
592 | //assert(e2deg <= 1);
593 | // extended gcd again: d = gcd(d1, v1+v2) = c1*d1 + c2*(v1+v2)
594 | //ui64 b[3] = {residue_add(v1[0], v2[0]), residue_add(v1[1], v2[1]), 0};
595 | $b = Array(residue_add($v1[0], $v2[0]), residue_add($v1[1], $v2[1]), gmp_init(0));
596 | //int bdeg = (b[1] == 0 ? (b[0] == 0 ? -1 : 0) : 1);
597 | $bdeg = 1;
598 | if(gmp_cmp($b[1], 0) == 0) {
599 | if(gmp_cmp($b[0], 0) == 0) {
600 | $bdeg = -1;
601 | } else {
602 | $bdeg = 0;
603 | }
604 | }
605 | //for($i=0;$i<3;$i++) {
606 | // echo("b[$i]: ".strval($b[$i])."\n");
607 | //}
608 |
609 | //int ddeg, c1deg, c2deg;
610 | $ddeg = 0;
611 | $c1deg = 0;
612 | $c2deg = 0;
613 | //ui64 d[3], c1[3], c2[3];
614 | $d = Array($gmp0,$gmp0,$gmp0);
615 | $c1 = Array($gmp0,$gmp0,$gmp0);
616 | $c2 = Array($gmp0,$gmp0,$gmp0);
617 | polynomial_xgcd($d1deg, $d1, $bdeg, $b, $ddeg, $d, $c1deg, $c1, $c2deg, $c2);
618 |
619 | //echo("ddeg: $u1deg\n");
620 | //echo("c1deg: $c1deg\n");
621 | //echo("c2deg: $c2deg\n");
622 |
623 | /*
624 | for($i=0;$i<3;$i++) {
625 | echo("d[$i]: ".strval($d[$i])."\n");
626 | }
627 | for($i=0;$i<3;$i++) {
628 | echo("c1[$i]: ".strval($c1[$i])."\n");
629 | }
630 | for($i=0;$i<3;$i++) {
631 | echo("c2[$i]: ".strval($c2[$i])."\n");
632 | }*/
633 |
634 | //assert(c1deg <= 0);
635 | //assert(c2deg <= 1);
636 | //assert(ddeg >= 0);
637 | $dmult = residue_inv($d[$ddeg]); // ui64
638 |
639 | for ($i = 0; $i < $ddeg; $i++)
640 | $d[$i] = residue_mul($d[$i], $dmult);
641 | $d[$i] = 1;
642 | for ($i = 0; $i <= $c1deg; $i++)
643 | $c1[$i] = residue_mul($c1[$i], $dmult);
644 | for ($i = 0; $i <= $c2deg; $i++)
645 | $c2[$i] = residue_mul($c2[$i], $dmult);
646 | //ui64 u[5];
647 | $u = Array($gmp0,$gmp0,$gmp0,$gmp0,$gmp0);
648 | // echo("u1deg, u2deg: $u1deg $u2deg\n");
649 | // for($i=0;$i<3;$i++) {
650 | // echo("u1[$i]: ".strval($u1[$i])."\n");
651 | // }
652 | // for($i=0;$i<3;$i++) {
653 | // echo("u2[$i]: ".strval($u2[$i])."\n");
654 | // }
655 |
656 | $udeg = polynomial_mul($u1deg, $u1, $u2deg, $u2, -1, $u); // int
657 | // for($i=0;$i<5;$i++) {
658 | // echo("u[$i]: ".strval($u[$i])."\n");
659 | // }
660 | // echo("udeg: $udeg\n");
661 | // u is monic
662 | //ui64 v[7], tmp[7];
663 | $v = Array($gmp0,$gmp0,$gmp0,$gmp0,$gmp0,$gmp0,$gmp0);
664 | $tmp = Array($gmp0,$gmp0,$gmp0,$gmp0,$gmp0,$gmp0,$gmp0);
665 | //int vdeg, tmpdeg;
666 | $vdeg = 0;
667 | $tmpdeg = 0;
668 | // c1*(e1*u1*v2 + e2*u2*v1) + c2*(v1*v2 + f)
669 | // c1*(e1*u1*(v2-v1) + d1*v1) + c2*(v1*v2 + f)
670 | $v[0] = residue_sub($v2[0], $v1[0]);
671 | $v[1] = residue_sub($v2[1], $v1[1]);
672 | $tmpdeg = polynomial_mul($e1deg, $e1, 1, $v, -1, $tmp);
673 | $vdeg = polynomial_mul($u1deg, $u1, $tmpdeg, $tmp, -1, $v);
674 | $vdeg = polynomial_mul($d1deg, $d1, 1, $v1, $vdeg, $v);
675 | for ($i = 0; $i <= $vdeg; $i++)
676 | $v[$i] = residue_mul($v[$i], $c1[0]);
677 | //memcpy(tmp, f, 6 * sizeof(f[0]));
678 | for($iii = 0; $iii < 6; $iii++) {
679 | $tmp[$iii] = $f[$iii];
680 | }
681 |
682 | $tmpdeg = 5;
683 | $tmpdeg = polynomial_mul(1, $v1, 1, $v2, $tmpdeg, $tmp);
684 | $vdeg = polynomial_mul($c2deg, $c2, $tmpdeg, $tmp, $vdeg, $v);
685 | //echo("udeg, ddeg: $udeg $ddeg\n");
686 | if ($ddeg > 0) {
687 | //assert(udeg >= 2*ddeg);
688 | //ui64 udiv[5];
689 | $udiv = Array($gmp0,$gmp0,$gmp0,$gmp0,$gmp0);
690 | polynomial_div_monic($udeg, $u, $ddeg, $d, $udiv); $udeg -= $ddeg;
691 | polynomial_div_monic($udeg, $udiv, $ddeg, $d, $u); $udeg -= $ddeg;
692 | if ($vdeg >= 0) {
693 | //assert(vdeg >= ddeg);
694 | polynomial_div_monic($vdeg, $v, $ddeg, $d, $udiv); $vdeg -= $ddeg;
695 | //memcpy(v, udiv, (vdeg + 1) * sizeof(v[0])); what the?
696 | for($iii = 0; $iii < ($vdeg + 1); $iii++) {
697 | $v[$iii] = $udiv[$iii];
698 | }
699 | }
700 | }
701 | $empty = gmp_init(0); // NULL placeholder
702 | $vdeg = polynomial_div_monic($vdeg, $v, $udeg, $u, $empty);
703 | while ($udeg > 2) {
704 | //assert(udeg <= 4);
705 | //assert(vdeg <= 3);
706 | // u' = monic((f-v^2)/u), v'=-v mod u'
707 | $tmpdeg = polynomial_mul($vdeg, $v, $vdeg, $v, -1, $tmp);
708 | for ($i = 0; $i <= $tmpdeg && $i <= 5; $i++)
709 | $tmp[$i] = residue_sub($f[$i], $tmp[$i]);
710 | for (; $i <= $tmpdeg; $i++)
711 | $tmp[$i] = residue_sub(0, $tmp[$i]);
712 | for (; $i <= 5; $i++)
713 | $tmp[$i] = $f[$i];
714 | $tmpdeg = $i - 1;
715 | $udiv = Array($gmp0,$gmp0,$gmp0,$gmp0,$gmp0);
716 | polynomial_div_monic($tmpdeg, $tmp, $udeg, $u, $udiv);
717 | $udeg = $tmpdeg - $udeg;
718 | $mult = residue_inv($udiv[$udeg]); // uint64
719 | for ($i = 0; $i < $udeg; $i++)
720 | $u[$i] = residue_mul($udiv[$i], $mult);
721 | $u[$i] = 1;
722 | for ($i = 0; $i <= $vdeg; $i++)
723 | $v[$i] = residue_sub(0, $v[$i]);
724 | $empty = 0;
725 | $vdeg = polynomial_div_monic($vdeg, $v, $udeg, $u, $empty);
726 | }
727 | if ($udeg == 2) {
728 | $dst->u[0] = $u[0];
729 | $dst->u[1] = $u[1];
730 | //$dst->v[0] = (vdeg >= 0 ? v[0] : 0);
731 | if($vdeg>=0) {
732 | $dst->v[0] = $v[0];
733 | } else {
734 | $dst->v[0] = 0;
735 | }
736 | //$dst->v[1] = (vdeg >= 1 ? v[1] : 0);
737 | if($vdeg>=1) {
738 | $dst->v[1] = $v[1];
739 | } else {
740 | $dst->v[1] = 0;
741 | }
742 | } else if ($udeg == 1) {
743 | $dst->u[0] = $u[0];
744 | $dst->u[1] = $BAD;
745 | //$dst->v[0] = (vdeg >= 0 ? v[0] : 0);
746 | if($vdeg>=0) {
747 | $dst->v[0] = $v[0];
748 | } else {
749 | $dst->v[0] = 0;
750 | }
751 | $dst->v[1] = $BAD;
752 | } else {
753 | //assert(udeg == 0);
754 | $dst->u[0] = $BAD;
755 | $dst->u[1] = $BAD;
756 | $dst->v[0] = $BAD;
757 | $dst->v[1] = $BAD;
758 | }
759 | }
760 |
761 | // UNTESTED
762 | // #define divisor_double(src, dst) divisor_add(src, src, dst)
763 | function divisor_double($src, &$dst) {
764 | return divisor_add($src, $src, $dst);
765 | }
766 |
767 | // UNTESTED
768 | function divisor_mul(&$src, $mult, &$dst) { //static void divisor_mul(const TDivisor* src, ui64 mult, TDivisor* dst)
769 | // mult is uint64
770 | global $BAD;
771 |
772 | if (gmp_cmp($mult, 0) == 0) {
773 | $dst->u[0] = $BAD;
774 | $dst->u[1] = $BAD;
775 | $dst->v[0] = $BAD;
776 | $dst->v[1] = $BAD;
777 | return;
778 | }
779 | //TDivisor cur = *src; this defines cur and copies src to cur
780 | $cur = new TDivisor();
781 | $cur->u = Array($src->u[0],$src->u[1]);
782 | $cur->v = Array($src->v[0],$src->v[1]);
783 |
784 | while (!(gmp_cmp(gmp_and($mult, 1),0)>0)) {
785 | divisor_double($cur, $cur);
786 | $mult = uint64(gmp_shiftr($mult,1));
787 | }
788 | // *dst = cur; copy cur to dst
789 | $dst->u = Array($cur->u[0],$cur->u[1]);
790 | $dst->v = Array($cur->v[0],$cur->v[1]);
791 |
792 | $mult = uint64(gmp_shiftr($mult,1));
793 | while(gmp_cmp($mult, 0) != 0) {// while ((mult >>= 1) != 0) {
794 | divisor_double($cur, $cur);
795 | if (gmp_cmp(gmp_and($mult, 1), 0) > 0)
796 | divisor_add($dst, $cur, $dst);
797 | $mult = uint64(gmp_shiftr($mult,1));
798 | }
799 | }
800 |
801 | // UNTESTED
802 | function divisor_mul128($src, $mult_lo, $mult_hi, &$dst) { // static void divisor_mul128(const TDivisor* src, ui64 mult_lo, ui64 mult_hi, TDivisor* dst)
803 | // mult_lo and mult_hi are uint64
804 | global $BAD;
805 |
806 | if (gmp_cmp($mult_lo,0) == 0 && gmp_cmp($mult_hi, 0) == 0) {
807 | $dst->u[0] = $BAD;
808 | $dst->u[1] = $BAD;
809 | $dst->v[0] = $BAD;
810 | $dst->v[1] = $BAD;
811 | return;
812 | }
813 | //TDivisor cur = *src;
814 | $cur = new TDivisor();
815 |
816 | $cur->u = Array($src->u[0],$src->u[1]);
817 | $cur->v = Array($src->v[0],$src->v[1]);
818 |
819 |
820 | while (!(gmp_cmp(gmp_and($mult_lo, 1),0)>0)) {
821 | divisor_double($cur, $cur);
822 |
823 | $mult_lo = uint64(gmp_shiftr($mult_lo, 1));
824 | if (gmp_cmp(gmp_and($mult_hi, 1), 0) > 0)
825 | $mult_lo = uint64(gmp_or($mult_lo,uint64(gmp_shiftl(1,63))));
826 | $mult_hi = uint64(gmp_shiftr($mult_hi, 1));
827 | }
828 | // *dst = cur;
829 | $dst->u = Array($cur->u[0],$cur->u[1]);
830 | $dst->v = Array($cur->v[0],$cur->v[1]);
831 |
832 |
833 |
834 | for (;;) {
835 | $mult_lo = uint64(gmp_shiftr($mult_lo, 1));
836 | if (gmp_cmp(gmp_and($mult_hi, 1), 0) > 0)
837 | $mult_lo = uint64(gmp_or($mult_lo,uint64(gmp_shiftl(1,63))));
838 | $mult_hi = uint64(gmp_shiftr($mult_hi, 1));
839 | if (gmp_cmp($mult_lo, 0) == 0 && gmp_cmp($mult_hi, 0) == 0)
840 | break;
841 | divisor_double($cur, $cur);
842 | //echo("\nu0: " . gmp_strval($cur->u[0]));
843 | //echo("\nu1: " . gmp_strval($cur->u[1]));
844 | //echo("\nv0: " . gmp_strval($cur->v[0]));
845 | //echo("\nv1: " . gmp_strval($cur->v[1]) . "\n");
846 |
847 | if (gmp_cmp(gmp_and($mult_lo, 1), 0) > 0) {
848 | divisor_add($dst, $cur, $dst);
849 | }
850 | }
851 | }
852 |
853 | function rol($x, $shift) {
854 | //assert(shift > 0 && shift < 32);
855 | if(gettype($shift)=="object") {
856 | $shift = gmp_intval($shift);
857 | }
858 | return uint32(gmp_or(gmp_shiftl($x, $shift), gmp_shiftr($x, (32 - $shift))));
859 | }
860 |
861 | // array fun yay D: !!
862 | // UNTESTED
863 | function sha1_single_block($input, &$output) { //static void sha1_single_block(unsigned char input[64], unsigned char output[20])
864 | //unsigned a, b, c, d, e;
865 | $a = gmp_init("0x67452301");
866 | $b = gmp_init("0xEFCDAB89");
867 | $c = gmp_init("0x98BADCFE");
868 | $d = gmp_init("0x10325476");
869 | $e = gmp_init("0xC3D2E1F0");
870 | //unsigned w[80];
871 | $w = Array();
872 |
873 | for ($i = 0; $i < 16; $i++) { // ok
874 | $w[$i] = uint32(gmp_or(gmp_or(gmp_or(gmp_shiftl($input[4*$i], 24), gmp_shiftl($input[4*$i+1], 16)), gmp_shiftl($input[4*$i+2], 8)), $input[4*$i+3]));
875 | }
876 | for ($i = 16; $i < 80; $i++) { // ok
877 | $w[$i] = rol(gmp_xor(gmp_xor(gmp_xor($w[$i - 3], $w[$i - 8]), $w[$i - 14]), $w[$i - 16]), 1);
878 | //echo($w[$i] . " ");
879 | }
880 |
881 | for ($i = 0; $i < 20; $i++) { // ?
882 | // for ~b
883 | //echo("A STEP1: $a\n");
884 | // bitwse not on b
885 | $b_inv = gmp_intval($b);
886 | $b_inv = ~$b_inv;
887 | $b_inv = $b_inv & 0xFFFFFFFF;
888 | $b_inv = gmp_init($b_inv);
889 | //$tmp = rol(a, tmp) + ((b & c) | (~b & d)) + e + w[i] + 0x5A827999;
890 | $tmp = uint32(gmp_or(gmp_and($b,$c),gmp_and($b_inv,$d)));
891 | //echo("A STEP2: $tmp\n");
892 | $tmp = uint32(gmp_add($tmp, rol($a, 5)));
893 | //echo("A STEP3: $tmp\n");
894 | $tmp = uint32(gmp_add($tmp,$e));
895 | //echo("A STEP4: $tmp\n");
896 | $tmp = uint32(gmp_add($tmp,$w[$i]));
897 | //echo("A STEP5: $tmp\n");
898 | $tmp = uint32(gmp_add($tmp,gmp_init("0x5A827999")));
899 | //$tmp = uint32(gmp_add(gmp_add(gmp_add(rol($a, 5),gmp_or(gmp_and($b,$c),gmp_and($b_inv, $d))),$e),$w[$i]),gmp_init("0x5A827999"));
900 | //$tmp = uint32(gmp_add(uint32(gmp_add(uint32(gmp_add(gmp_add(rol($a, 5),gmp_or(gmp_and($b, $c), gmp_and($b_inv, $d))),$e)),$w[$i])),gmp_init("0x5A827999")) );
901 | $e = $d;
902 | $d = $c;
903 | $c = uint32(rol($b, 30));
904 | $b = $a;
905 | $a = $tmp;
906 |
907 | }
908 | // echo("\n");
909 | // echo("A: " . gmp_strval($a) . "\n");
910 | // echo("B: " . gmp_strval($b) . "\n");
911 | // echo("C: " . gmp_strval($c) . "\n");
912 | // echo("D: " . gmp_strval($d) . "\n");
913 | // echo("E: " . gmp_strval($e) . "\n");
914 |
915 | for ($i = 20; $i < 40; $i++) {
916 | //unsigned tmp = rol(a, 5) + (b ^ c ^ d) + e + w[i] + 0x6ED9EBA1;
917 | $tmp = uint32(gmp_add(gmp_add(gmp_add(gmp_add(rol($a, 5),gmp_xor(gmp_xor($b,$c),$d)),$e),$w[$i]),gmp_init("0x6ED9EBA1")));
918 | $e = $d;
919 | $d = $c;
920 | $c = rol($b, 30);
921 | $b = $a;
922 | $a = $tmp;
923 | }
924 | for ($i = 40; $i < 60; $i++) {
925 | //unsigned tmp = rol(a, 5) + ((b & c) | (b & d) | (c & d)) + e + w[i] + 0x8F1BBCDC;
926 | $tmp = uint32(gmp_add(gmp_add(gmp_add(gmp_add(rol($a,5),gmp_or(gmp_or(gmp_and($b, $c), gmp_and($b, $d)), gmp_and($c, $d))),$e),$w[$i]),gmp_init("0x8F1BBCDC")));
927 | $e = $d;
928 | $d = $c;
929 | $c = rol($b, 30);
930 | $b = $a;
931 | $a = $tmp;
932 | }
933 | for ($i = 60; $i < 80; $i++) {
934 | //unsigned tmp = rol(a, 5) + (b ^ c ^ d) + e + w[i] + 0xCA62C1D6;
935 | $tmp = uint32(gmp_add(gmp_add(gmp_add(gmp_add(rol($a,5), gmp_xor(gmp_xor($b, $c),$d)), $e), $w[$i]), gmp_init("0xCA62C1D6")));
936 | $e = $d;
937 | $d = $c;
938 | $c = rol($b, 30);
939 | $b = $a;
940 | $a = $tmp;
941 | }
942 | $a = uint32(gmp_add($a, gmp_init("0x67452301")));
943 | $b = uint32(gmp_add($b, gmp_init("0xEFCDAB89")));
944 | $c = uint32(gmp_add($c, gmp_init("0x98BADCFE")));
945 | $d = uint32(gmp_add($d, gmp_init("0x10325476")));
946 | $e = uint32(gmp_add($e, gmp_init("0xC3D2E1F0")));
947 |
948 | $output[0] = uint8(gmp_shiftr($a, 24)); $output[1] = uint8(gmp_shiftr($a, 16)); $output[2] = uint8(gmp_shiftr($a, 8)); $output[3] = uint8($a);
949 | $output[4] = uint8(gmp_shiftr($b, 24)); $output[5] = uint8(gmp_shiftr($b, 16)); $output[6] = uint8(gmp_shiftr($b, 8)); $output[7] = uint8($b);
950 | $output[8] = uint8(gmp_shiftr($c, 24)); $output[9] = uint8(gmp_shiftr($c, 16)); $output[10] = uint8(gmp_shiftr($c, 8)); $output[11] = uint8($c);
951 | $output[12] = uint8(gmp_shiftr($d, 24)); $output[13] = uint8(gmp_shiftr($d, 16)); $output[14] = uint8(gmp_shiftr($d, 8)); $output[15] = uint8($d);
952 | $output[16] = uint8(gmp_shiftr($e, 24)); $output[17] = uint8(gmp_shiftr($e, 16)); $output[18] = uint8(gmp_shiftr($e, 8)); $output[19] = uint8($e);
953 | }
954 |
955 | // UNTESTED
956 | function Mix(&$buffer, $bufSize, &$key, $keySize) { //static void Mix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize)
957 | //unsigned char sha1_input[64];
958 | $sha1_input = Array();
959 | //unsigned char sha1_result[20];
960 | $sha1_result = Array();
961 | $half = floor($bufSize / 2);
962 | //assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9);
963 | $external_counter = 0;
964 | for ($external_counter = 0; $external_counter < 4; $external_counter++) {
965 | //memset(sha1_input, 0, sizeof(sha1_input));
966 | for($iii=0;$iii<64;$iii++) {
967 | $sha1_input[$iii] = gmp_init(0);;
968 | }
969 | //memcpy(sha1_input, buffer + half, half);
970 | for($iii=0;$iii<$half;$iii++) {
971 | $sha1_input[$iii] = $buffer[$iii+$half];
972 | }
973 | //memcpy(sha1_input + half, key, keySize);
974 | for($iii=0;$iii<$keySize;$iii++) {
975 | $sha1_input[$iii + $half] = $key[$iii];
976 | }
977 | //sha1_input[half + keySize] = 0x80;
978 | $sha1_input[$half + $keySize] = gmp_init(0x80);
979 | //sha1_input[sizeof(sha1_input) - 1] = (half + keySize) * 8;
980 | $sha1_input[64 - 1] = uint8(gmp_mul(gmp_init(($half + $keySize)), 8));
981 | $sha1_input[64 - 2] = uint8(gmp_div(gmp_mul(gmp_init($half + $keySize), 8), 0x100));
982 |
983 |
984 | sha1_single_block($sha1_input, $sha1_result);
985 |
986 | for ($i = $half & ~3; $i < $half; $i++)
987 | $sha1_result[$i] = $sha1_result[$i + 4 - ($half & 3)];
988 | for ($i = 0; $i < $half; $i++) {
989 | $tmp = $buffer[$i + $half];
990 | $buffer[$i + $half] = gmp_xor($buffer[$i], $sha1_result[$i]);
991 | $buffer[$i] = $tmp;
992 | }
993 | }
994 | }
995 |
996 | // UNTESTED
997 | function Unmix(&$buffer, $bufSize, &$key, $keySize) { // static void Unmix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize)
998 | //unsigned char sha1_input[64];
999 | $sha1_input = Array();
1000 | //unsigned char sha1_result[20];
1001 | $sha1_result = Array();
1002 | $half = floor($bufSize / 2);
1003 |
1004 | //assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9);
1005 |
1006 | for ($external_counter = 0; $external_counter < 4; $external_counter++) {
1007 | //memset(sha1_input, 0, sizeof(sha1_input));
1008 | for($iii=0;$iii<64;$iii++) {
1009 | $sha1_input[$iii] = gmp_init(0);
1010 | }
1011 | //memcpy(sha1_input, buffer, half);
1012 | for($iii=0;$iii<$half;$iii++) {
1013 | $sha1_input[$iii] = $buffer[$iii];
1014 | }
1015 | //memcpy(sha1_input + half, key, keySize);
1016 | for($iii=0;$iii<$keySize;$iii++) {
1017 | $sha1_input[$iii+$half] = $key[$iii];
1018 | }
1019 | $sha1_input[$half + $keySize] = gmp_init(0x80);
1020 | $sha1_input[64 - 1] = uint8(gmp_mul(gmp_init(($half + $keySize)), 8));
1021 | $sha1_input[64 - 2] = uint8(gmp_div(gmp_mul(gmp_init($half + $keySize), 8), 0x100));
1022 |
1023 |
1024 | sha1_single_block($sha1_input, $sha1_result);
1025 |
1026 |
1027 | for ($i = $half & ~3; $i < $half; $i++) {
1028 | $sha1_result[$i] = $sha1_result[$i + 4 - ($half & 3)];
1029 | }
1030 | for ($i = 0; $i < $half; $i++) {
1031 | $tmp = $buffer[$i];
1032 | $buffer[$i] = gmp_xor($buffer[$i + $half], $sha1_result[$i]);
1033 | $buffer[$i + $half] = $tmp;
1034 | }
1035 | }
1036 | }
1037 |
1038 | $ERR_TOO_SHORT = 1;
1039 | $ERR_TOO_LARGE = 2;
1040 | $ERR_INVALID_CHARACTER = 3;
1041 | $ERR_INVALID_CHECK_DIGIT = 4;
1042 | $ERR_UNKNOWN_VERSION = 5;
1043 | $ERR_UNLUCKY = 6;
1044 |
1045 | // UNTESTED
1046 | function generate($installation_id_str, &$confirmation_id) { // static int generate(const CHARTYPE* installation_id_str, CHARTYPE confirmation_id[49])
1047 | global $ERR_TOO_SHORT, $ERR_TOO_LARGE, $ERR_INVALID_CHARACTER, $ERR_INVALID_CHECK_DIGIT, $ERR_UNKNOWN_VERSION, $ERR_UNLUCKY, $NON_RESIDUE, $MOD, $BAD;
1048 | $installation_id = Array(); //unsigned char installation_id[19]; // 10**45 < 256**19
1049 | $installation_id_len = 0; //size_t installation_id_len = 0;
1050 | $p = $installation_id_str;
1051 | $count = 0;
1052 | $totalCount = 0;
1053 | $check = 0; // unsigned
1054 | $plen = strlen($p);
1055 | for($pi=0;$pi<$plen;$pi++) { //for (; *p; p++) {
1056 | $pp = $p[$pi];
1057 | if ($pp == ' ' || $pp == '-')
1058 | continue;
1059 | /*
1060 | int d = *p - '0';
1061 | if (d < 0 || d > 9)
1062 | return ERR_INVALID_CHARACTER;
1063 | */
1064 | if(!is_numeric($pp)) {
1065 | return $ERR_INVALID_CHARACTER;
1066 | }
1067 | $d = intval($pp);
1068 | if ($count == 5 || ord($p[$pi+1]) == 0) {
1069 | if (!$count)
1070 | return ($totalCount == 45) ? $ERR_TOO_LARGE : $ERR_TOO_SHORT;
1071 | if ($d != $check % 7)
1072 | return ($count < 5) ? $ERR_TOO_SHORT : $ERR_INVALID_CHECK_DIGIT;
1073 | $check = 0;
1074 | $count = 0;
1075 | continue;
1076 | }
1077 | $check += ($count % 2 ? $d * 2 : $d);
1078 | $count++;
1079 | $totalCount++;
1080 | if ($totalCount > 45)
1081 | return $ERR_TOO_LARGE;
1082 | $carry = uint8(gmp_init($d)); // unsigned char
1083 | for ($i = 0; $i < $installation_id_len; $i++) {
1084 | $x = uint32(gmp_add(gmp_mul(gmp_init($installation_id[$i]), 10), $carry)); // unsigned
1085 | $installation_id[$i] = gmp_intval(gmp_and($x, 0xFF));
1086 | $carry = gmp_intval(uint8(gmp_shiftr($x, 8)));
1087 | }
1088 | if (gmp_cmp($carry, 0) > 0) {
1089 | //assert(installation_id_len < sizeof(installation_id));
1090 | $installation_id[$installation_id_len++] = gmp_intval($carry);
1091 | }
1092 | }
1093 | if ($totalCount != 41 && $totalCount < 45)
1094 | return $ERR_TOO_SHORT;
1095 | for (; $installation_id_len < 19; $installation_id_len++)
1096 | $installation_id[$installation_id_len] = 0;
1097 | //static const unsigned char iid_key[4] = {0x6A, 0xC8, 0x5E, 0xD4};
1098 | $iid_key = Array(gmp_init(0x6A), gmp_init(0xC8), gmp_init(0x5E), gmp_init(0xD4));
1099 | // convert instalation id to gmp
1100 | for($iii=0;$iii<19;$iii++) {
1101 | $installation_id[$iii] = uint8(gmp_init($installation_id[$iii]));
1102 | }
1103 |
1104 | Unmix($installation_id, $totalCount == 41 ? 17 : 19, $iid_key, 4);
1105 | // convert it back to num (no need)
1106 | //for($iii=0;$iii<19;$iii++) {
1107 | // $installation_id[$iii] = gmp_intval($installation_id[$iii]);
1108 | //}
1109 |
1110 |
1111 | if (gmp_cmp($installation_id[18], 0x10) >= 0)
1112 | return $ERR_UNKNOWN_VERSION;
1113 |
1114 | // #pragma pack(push, 1)
1115 | /*
1116 | struct {
1117 | ui64 HardwareID;
1118 | ui64 ProductIDLow;
1119 | unsigned char ProductIDHigh;
1120 | unsigned short KeySHA1;
1121 | } parsed;
1122 | */
1123 | $parsed = new stdClass();
1124 | $parsed->HardwareID = gmp_init(0); // uint64
1125 | $parsed->ProductIDLow = gmp_init(0); // uint64
1126 | $parsed->ProductIDHigh = gmp_init(0); // uint8
1127 | $parsed->KeySHA1 = gmp_init(0); // uint16
1128 | // #pragma pack(pop)
1129 | //memcpy(&parsed, installation_id, sizeof(parsed));
1130 | // splitted into multiple lines to not make very long lines
1131 | $parsed->HardwareID = gmp_or(gmp_or(gmp_or($installation_id[0],gmp_shiftl($installation_id[1],8)),gmp_shiftl($installation_id[2],16)),gmp_shiftl($installation_id[3],24));
1132 | $parsed->HardwareID = gmp_or($parsed->HardwareID,gmp_or(gmp_or(gmp_or(gmp_shiftl($installation_id[4],32),gmp_shiftl($installation_id[5],40)),gmp_shiftl($installation_id[6],48)),gmp_shiftl($installation_id[7],56)));
1133 |
1134 | $parsed->ProductIDLow = gmp_or(gmp_or(gmp_or($installation_id[8],gmp_shiftl($installation_id[9],8)),gmp_shiftl($installation_id[10],16)),gmp_shiftl($installation_id[11],24));
1135 | $parsed->ProductIDLow = gmp_or($parsed->ProductIDLow,gmp_or(gmp_or(gmp_or(gmp_shiftl($installation_id[12],32),gmp_shiftl($installation_id[13],40)),gmp_shiftl($installation_id[14],48)),gmp_shiftl($installation_id[15],56)));
1136 |
1137 | $parsed->ProductIDHigh = $installation_id[16];
1138 |
1139 | $parsed->KeySHA1 = gmp_or($installation_id[17], gmp_shiftl($installation_id[18],8));
1140 | // end of memcpy
1141 |
1142 |
1143 | $productId1 = uint32(gmp_and($parsed->ProductIDLow, gmp_init((1 << 17) - 1))); // unsigned
1144 | $productId2 = uint32(gmp_and(gmp_shiftr($parsed->ProductIDLow, 17), gmp_init((1 << 10) - 1))); // unsigned
1145 | $productId3 = uint32(gmp_and(gmp_shiftr($parsed->ProductIDLow, 27), gmp_init((1 << 25) - 1))); // unsigned
1146 | $version = uint32(gmp_and(gmp_shiftr($parsed->ProductIDLow, 52), 7)); // unsigned
1147 | $productId4 = uint32(gmp_or(gmp_shiftr($parsed->ProductIDLow, 55), gmp_shiftl($parsed->ProductIDHigh, 9))); // unsigned
1148 | if (gmp_cmp($version, gmp_init($totalCount == 41 ? 4 : 5))!=0)
1149 | return $ERR_UNKNOWN_VERSION;
1150 | //printf("Product ID: %05u-%03u-%07u-%05u\n", productId1, productId2, productId3, productId4);
1151 |
1152 |
1153 | $keybuf = Array(); //unsigned char keybuf[16]; // unsigned char
1154 | //memcpy(keybuf, &parsed.HardwareID, 8);
1155 | // parsed->HardwareID is basically $installation_id[0 .. 7]
1156 | for($iii=0;$iii<8;$iii++) {
1157 | $keybuf[$iii] = $installation_id[$iii];
1158 | }
1159 |
1160 | $productIdMixed = gmp_or(gmp_or(gmp_or(uint64(gmp_shiftl($productId1, 41)), uint64(gmp_shiftl($productId2, 58))), uint64(gmp_shiftl($productId3, 17))), uint64($productId4)); // uint64
1161 | //memcpy(keybuf + 8, &productIdMixed, 8);
1162 | // 0x1122334455667788 -> array[0] = 0x88, array[1] = 0x77 and on...
1163 |
1164 | for($iii=0;$iii<8;$iii++) {
1165 | $keybuf[$iii+8] = uint8(gmp_and(gmp_shiftr($productIdMixed, $iii*8), gmp_init(0xFF)));
1166 | }
1167 |
1168 |
1169 | //TDivisor d;
1170 | $d = new TDivisor();
1171 | $d->u = Array(gmp_init(0),gmp_init(0));
1172 | $d->v = Array(gmp_init(0),gmp_init(0));
1173 |
1174 | //$attempt - unsigned char
1175 | for ($attempt = 0; $attempt <= 0x80; $attempt++) {
1176 | //echo("attempt: $attempt\n");
1177 | /*union {
1178 | unsigned char buffer[14];
1179 | struct {
1180 | ui64 lo;
1181 | ui64 hi;
1182 | };
1183 | } u;
1184 | union makes char and the both ui64 be at the same memory
1185 | u.buffer[0] = 0x64 makes u.lo = 0x64
1186 | */
1187 | $u = new stdClass();
1188 | $u->lo = gmp_init(0);
1189 | $u->hi = gmp_init(0);
1190 | $u->buffer = Array();
1191 | for($iii=0;$iii<14;$iii++) {
1192 | $u->buffer[$iii] = gmp_init(0);
1193 | }
1194 | $u->buffer[7] = uint8(gmp_init($attempt));
1195 |
1196 | Mix($u->buffer, 14, $keybuf, 16);
1197 |
1198 | // copy buffer to lo and hi
1199 | $u->lo = gmp_or(gmp_or(gmp_or($u->buffer[0],gmp_shiftl($u->buffer[1],8)),gmp_shiftl($u->buffer[2],16)),gmp_shiftl($u->buffer[3],24));
1200 | $u->lo = gmp_or($u->lo,gmp_or(gmp_or(gmp_or(gmp_shiftl($u->buffer[4],32),gmp_shiftl($u->buffer[5],40)),gmp_shiftl($u->buffer[6],48)),gmp_shiftl($u->buffer[7],56)));
1201 |
1202 | $u->hi = gmp_or(gmp_or(gmp_or($u->buffer[8],gmp_shiftl($u->buffer[9],8)),gmp_shiftl($u->buffer[10],16)),gmp_shiftl($u->buffer[11],24));
1203 | $u->hi = gmp_or($u->hi,gmp_or(gmp_shiftl($u->buffer[12],32),gmp_shiftl($u->buffer[13],40)));
1204 |
1205 | $x2 = ui128_quotient_mod($u->lo, $u->hi); //ui64
1206 | $x1 = uint64(gmp_sub($u->lo, uint64(gmp_mul($x2, $MOD)))); // ui64
1207 | $x2 = uint64(gmp_add($x2, 1));//x2++;
1208 | $d->u[0] = residue_sub(residue_mul($x1, $x1), residue_mul($NON_RESIDUE, residue_mul($x2, $x2)));
1209 | $d->u[1] = residue_add($x1, $x1);
1210 | if (find_divisor_v($d))
1211 | break;
1212 | }
1213 | if ($attempt > 0x80)
1214 | return $ERR_UNLUCKY;
1215 |
1216 |
1217 | divisor_mul128($d, gmp_init("0x04e21b9d10f127c1"), gmp_init("0x40da7c36d44c"), $d);
1218 |
1219 |
1220 | /*union {
1221 | struct {
1222 | ui64 encoded_lo, encoded_hi;
1223 | };
1224 | struct {
1225 | uint32_t encoded[4];
1226 | };
1227 | } e;
1228 | */
1229 | $e = new stdClass();
1230 | $e->encoded_lo = gmp_init(0);
1231 | $e->encoded_hi = gmp_init(0);
1232 | $e->encoded = Array(gmp_init(0),gmp_init(0),gmp_init(0),gmp_init(0));
1233 |
1234 | if ($d->u[0] == $BAD) {
1235 | // we can not get the zero divisor, actually...
1236 | $e->encoded_lo = __umul128(uint64(gmp_add($MOD, gmp_init(2))), $MOD, $e->encoded_hi);
1237 | } else if ($d->u[1] == $BAD) {
1238 | // O(1/MOD) chance
1239 | //encoded = (unsigned __int128)(MOD + 1) * d.u[0] + MOD; // * MOD + d.u[0] is fine too
1240 | $e->encoded_lo = __umul128(uint64(gmp_add($MOD, 1)), $d->u[0], $e->encoded_hi);
1241 | $e->encoded_lo = uint64(gmp_add($e->encoded_lo, $MOD));
1242 | if(gmp_cmp($e->encoded_lo, $MOD)<0) { // e.encoded_hi += (e.encoded_lo < MOD);
1243 | $e->encoded_hi = uint64(gmp_add($e->encoded_hi, 1));
1244 | }
1245 |
1246 | } else {
1247 | //x1 = (d.u[1] % 2 ? d.u[1] + MOD : d.u[1]) / 2; // ui64
1248 | if(gmp_cmp(gmp_mod($d->u[1],gmp_init(2)),0)>0) {
1249 | $x1 = uint64(gmp_div(uint64(gmp_add($d->u[1], $MOD)),2));
1250 | } else {
1251 | $x1 = uint64(gmp_div($d->u[1],2));
1252 | }
1253 | $x2sqr = residue_sub(residue_mul($x1, $x1), $d->u[0]); // ui64
1254 | $x2 = residue_sqrt($x2sqr); // ui64
1255 | if (gmp_cmp($x2, $BAD) == 0) {
1256 | $x2 = residue_sqrt(residue_mul($x2sqr, residue_inv($NON_RESIDUE)));
1257 | //assert(x2 != BAD);
1258 | $e->encoded_lo = __umul128(uint64(gmp_add($MOD, 1)), uint64(gmp_add($MOD, $x2)), $e->encoded_hi);
1259 | $e->encoded_lo = uint64(gmp_add($e->encoded_lo, $x1));
1260 | if(gmp_cmp($e->encoded_lo, $x1)<0) { // e.encoded_hi += (e.encoded_lo < x1);
1261 | $e->encoded_hi = uint64(gmp_add($e->encoded_hi,1));
1262 | }
1263 |
1264 | } else {
1265 | // points (-x1+x2, v(-x1+x2)) and (-x1-x2, v(-x1-x2))
1266 | // all ui64
1267 | $x1a = residue_sub($x1, $x2);
1268 | $y1 = residue_sub($d->v[0], residue_mul($d->v[1], $x1a));
1269 | $x2a = residue_add($x1, $x2);
1270 | $y2 = residue_sub($d->v[0], residue_mul($d->v[1], $x2a));
1271 | if (gmp_cmp($x1a, $x2a)>0) {
1272 | $tmp = $x1a; //ui64
1273 | $x1a = $x2a;
1274 | $x2a = $tmp;
1275 | }
1276 | //if ((y1 ^ y2) & 1) {
1277 | if(gmp_cmp(gmp_and(gmp_xor($y1, $y2), 1), 0)>0) {
1278 | $tmp = $x1a;
1279 | $x1a = $x2a;
1280 | $x2a = $tmp;
1281 | }
1282 | $e->encoded_lo = __umul128(uint64(gmp_add($MOD, 1)), $x1a, $e->encoded_hi);
1283 | $e->encoded_lo = uint64(gmp_add($e->encoded_lo, $x2a));
1284 | //e.encoded_hi += (e.encoded_lo < x2a);
1285 | if(gmp_cmp($e->encoded_lo, $x2a) < 0) {
1286 | $e->encoded_hi = uint64(gmp_add($e->encoded_hi, 1));
1287 | }
1288 | }
1289 | }
1290 | $decimal = Array();//unsigned char decimal[35];
1291 | // convert e->encoeded_lo and e->encoded_hi to e->encoded
1292 | $e->encoded[0] = gmp_and($e->encoded_lo,gmp_init("0xFFFFFFFF"));
1293 | $e->encoded[1] = gmp_and(gmp_shiftr($e->encoded_lo,32),gmp_init("0xFFFFFFFF"));
1294 | $e->encoded[2] = gmp_and($e->encoded_hi,gmp_init("0xFFFFFFFF"));
1295 | $e->encoded[3] = gmp_and(gmp_shiftr($e->encoded_hi,32),gmp_init("0xFFFFFFFF"));
1296 |
1297 | for ($i = 0; $i < 35; $i++) {
1298 | $c = uint32(gmp_mod($e->encoded[3], 10)); // unsigned
1299 | $e->encoded[3] = uint32(gmp_div($e->encoded[3],10));
1300 | //unsigned c2 = ((ui64)c << 32 | e.encoded[2]) % 10;
1301 | $c2 = uint32(gmp_mod(gmp_or(uint64(gmp_shiftl($c,32)), $e->encoded[2]),10));
1302 | //e.encoded[2] = ((ui64)c << 32 | e.encoded[2]) / 10;
1303 | $e->encoded[2] = uint32(gmp_div(gmp_or(uint64(gmp_shiftl($c,32)), $e->encoded[2]),10));
1304 | //unsigned c3 = ((ui64)c2 << 32 | e.encoded[1]) % 10;
1305 | $c3 = uint32(gmp_mod(gmp_or(uint64(gmp_shiftl($c2,32)), $e->encoded[1]),10));
1306 | //e.encoded[1] = ((ui64)c2 << 32 | e.encoded[1]) / 10;
1307 | $e->encoded[1] = uint32(gmp_div(gmp_or(uint64(gmp_shiftl($c2,32)), $e->encoded[1]),10));
1308 | //unsigned c4 = ((ui64)c3 << 32 | e.encoded[0]) % 10;
1309 | $c4 = uint32(gmp_mod(gmp_or(uint64(gmp_shiftl($c3,32)), $e->encoded[0]),10));
1310 | //e.encoded[0] = ((ui64)c3 << 32 | e.encoded[0]) / 10;
1311 | $e->encoded[0] = uint32(gmp_div(gmp_or(uint64(gmp_shiftl($c3,32)), $e->encoded[0]),10));
1312 | $decimal[34 - $i] = uint8($c4);
1313 | }
1314 | //assert(e.encoded[0] == 0 && e.encoded[1] == 0 && e.encoded[2] == 0 && e.encoded[3] == 0);
1315 | //CHARTYPE* q = confirmation_id;
1316 | $q = $confirmation_id;
1317 | $qi = 0;
1318 | // convert $decimal gmp to int
1319 | for($iii=0;$iii<35;$iii++) {
1320 | $decimal[$iii]=gmp_intval($decimal[$iii]);
1321 | }
1322 | for ($i = 0; $i < 7; $i++) {
1323 | if ($i) { //*q++ = '-';
1324 | $q[$qi] = '-';
1325 | $qi++;
1326 | }
1327 |
1328 | $pi = $i*5;
1329 | /*unsigned char* p = decimal + i*5;
1330 | q[0] = p[0] + '0';
1331 | q[1] = p[1] + '0';
1332 | q[2] = p[2] + '0';
1333 | q[3] = p[3] + '0';
1334 | q[4] = p[4] + '0';
1335 | */
1336 | $zero = ord('0');
1337 | $q[$qi+0] = chr($decimal[$pi+0] + $zero);
1338 | $q[$qi+1] = chr($decimal[$pi+1] + $zero);
1339 | $q[$qi+2] = chr($decimal[$pi+2] + $zero);
1340 | $q[$qi+3] = chr($decimal[$pi+3] + $zero);
1341 | $q[$qi+4] = chr($decimal[$pi+4] + $zero);
1342 |
1343 | //q[5] = ((p[0]+p[1]*2+p[2]+p[3]*2+p[4]) % 7) + '0';
1344 | $q[$qi+5] = chr((($decimal[$pi+0]+$decimal[$pi+1]*2+$decimal[$pi+2]+$decimal[$pi+3]*2+$decimal[$pi+4]) % 7) + $zero);
1345 | //q += 6;
1346 | $qi = $qi + 6;
1347 | }
1348 | //*q++ = 0;
1349 | $qi++;
1350 | //$q[$qi] = 0;
1351 | // copy $q to $confirmation_id
1352 | $confirmation_id = $q;
1353 |
1354 | return 0;
1355 | }
1356 |
1357 |
1358 |
1359 | ?>
1360 |
--------------------------------------------------------------------------------