├── 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 | --------------------------------------------------------------------------------