function recoverPubKey($r, $s, $e, $recoveryFlags, $G)
{
    $isYEven = ($recoveryFlags & 1) != 0;
    $isSecondKey = ($recoveryFlags & 2) != 0;
    $curve = $G->getCurve();
    $signature = new Signature($r, $s);
    // Precalculate (p + 1) / 4 where p is the field order
    static $p_over_four;
    // XXX just assuming only one curve/prime will be used
    if (!$p_over_four) {
        $p_over_four = gmp_div(gmp_add($curve->getPrime(), 1), 4);
    }
    // 1.1 Compute x
    if (!$isSecondKey) {
        $x = $r;
    } else {
        $x = gmp_add($r, $G->getOrder());
    }
    // 1.3 Convert x to point
    $alpha = gmp_mod(gmp_add(gmp_add(gmp_pow($x, 3), gmp_mul($curve->getA(), $x)), $curve->getB()), $curve->getPrime());
    $beta = NumberTheory::modular_exp($alpha, $p_over_four, $curve->getPrime());
    // If beta is even, but y isn't or vice versa, then convert it,
    // otherwise we're done and y == beta.
    if (isBignumEven($beta) == $isYEven) {
        $y = gmp_sub($curve->getPrime(), $beta);
    } else {
        $y = $beta;
    }
    // 1.4 Check that nR is at infinity (implicitly done in construtor)
    $R = new Point($curve, $x, $y, $G->getOrder());
    $point_negate = function ($p) {
        return new Point($p->curve, $p->x, gmp_neg($p->y), $p->order);
    };
    // 1.6.1 Compute a candidate public key Q = r^-1 (sR - eG)
    $rInv = NumberTheory::inverse_mod($r, $G->getOrder());
    $eGNeg = $point_negate(Point::mul($e, $G));
    $Q = Point::mul($rInv, Point::add(Point::mul($s, $R), $eGNeg));
    // 1.6.2 Test Q as a public key
    $Qk = new PublicKey($G, $Q);
    if ($Qk->verifies($e, $signature)) {
        return $Qk;
    }
    return false;
}
Example #2
0
 public function sign($hash, $random_k)
 {
     if (extension_loaded('gmp') && USE_EXT == 'GMP') {
         $G = $this->public_key->getGenerator();
         $n = $G->getOrder();
         $k = gmp_Utils::gmp_mod2($random_k, $n);
         $p1 = Point::mul($k, $G);
         $r = $p1->getX();
         if (gmp_cmp($r, 0) == 0) {
             throw new ErrorException("error: random number R = 0 <br />");
         }
         $s = gmp_Utils::gmp_mod2(gmp_mul(NumberTheory::inverse_mod($k, $n), gmp_Utils::gmp_mod2(gmp_add($hash, gmp_mul($this->secret_multiplier, $r)), $n)), $n);
         if (gmp_cmp($s, 0) == 0) {
             throw new ErrorExcpetion("error: random number S = 0<br />");
         }
         return new Signature($r, $s);
     } else {
         if (extension_loaded('bcmath') && USE_EXT == 'BCMATH') {
             $G = $this->public_key->getGenerator();
             $n = $G->getOrder();
             $k = bcmod($random_k, $n);
             $p1 = Point::mul($k, $G);
             $r = $p1->getX();
             if (bccomp($r, 0) == 0) {
                 throw new ErrorException("error: random number R = 0 <br />");
             }
             $s = bcmod(bcmul(NumberTheory::inverse_mod($k, $n), bcmod(bcadd($hash, bcmul($this->secret_multiplier, $r)), $n)), $n);
             if (bccomp($s, 0) == 0) {
                 throw new ErrorExcpetion("error: random number S = 0<br />");
             }
             return new Signature($r, $s);
         } else {
             throw new ErrorException("Please install BCMATH or GMP");
         }
     }
 }
 public function verifies($hash, Signature $signature)
 {
     if (extension_loaded('gmp') && USE_EXT == 'GMP') {
         $G = $this->generator;
         $n = $this->generator->getOrder();
         $point = $this->point;
         $r = $signature->getR();
         $s = $signature->getS();
         if (gmp_cmp($r, 1) < 0 || gmp_cmp($r, gmp_sub($n, 1)) > 0) {
             return false;
         }
         if (gmp_cmp($s, 1) < 0 || gmp_cmp($s, gmp_sub($n, 1)) > 0) {
             return false;
         }
         $c = NumberTheory::inverse_mod($s, $n);
         $u1 = gmp_Utils::gmp_mod2(gmp_mul($hash, $c), $n);
         $u2 = gmp_Utils::gmp_mod2(gmp_mul($r, $c), $n);
         $xy = Point::add(Point::mul($u1, $G), Point::mul($u2, $point));
         $v = gmp_Utils::gmp_mod2($xy->getX(), $n);
         if (gmp_cmp($v, $r) == 0) {
             return true;
         } else {
             return false;
         }
     } else {
         if (extension_loaded('bcmath') && USE_EXT == 'BCMATH') {
             $G = $this->generator;
             $n = $this->generator->getOrder();
             $point = $this->point;
             $r = $signature->getR();
             $s = $signature->getS();
             if (bccomp($r, 1) == -1 || bccomp($r, bcsub($n, 1)) == 1) {
                 return false;
             }
             if (bccomp($s, 1) == -1 || bccomp($s, bcsub($n, 1)) == 1) {
                 return false;
             }
             $c = NumberTheory::inverse_mod($s, $n);
             $u1 = bcmod(bcmul($hash, $c), $n);
             $u2 = bcmod(bcmul($r, $c), $n);
             $xy = Point::add(Point::mul($u1, $G), Point::mul($u2, $point));
             $v = bcmod($xy->getX(), $n);
             if (bccomp($v, $r) == 0) {
                 return true;
             } else {
                 return false;
             }
         } else {
             throw new ErrorException("Please install BCMATH or GMP");
         }
     }
 }
 public static function bcmath_multInverseModP($verbose = false)
 {
     $start_time = microtime(true);
     $n_tests = 0;
     for ($i = 0; $i < 100; $i++) {
         $m = rand(20, 10000);
         for ($j = 0; $j < 100; $j++) {
             $a = rand(1, $m - 1);
             if (NumberTheory::gcd2($a, $m) == 1) {
                 $n_tests++;
                 $inv = NumberTheory::inverse_mod($a, $m);
                 if ($inv <= 0 || $inv >= $m || $a * $inv % $m != 1) {
                     $error_tally++;
                     print "{$inv} = inverse_mod( {$a}, {$m} ) is wrong.<br />\n";
                     flush();
                 } else {
                     if ($verbose) {
                         print "{$inv} = inverse_mod( {$a}, {$m} ) is CORRECT.<br />\n";
                     }
                     flush();
                 }
             }
         }
     }
     $end_time = microtime(true);
     $time_res = $end_time - $start_time;
     echo "<br />Multiplicative inverse mod arbitrary primes took: " . $time_res . " seconds. <br />";
     flush();
 }
 public static function double(Point $p1)
 {
     if (extension_loaded('gmp') && USE_EXT == 'GMP') {
         $p = $p1->curve->getPrime();
         $a = $p1->curve->getA();
         $inverse = NumberTheory::inverse_mod(gmp_strval(gmp_mul(2, $p1->y)), $p);
         $three_x2 = gmp_mul(3, gmp_pow($p1->x, 2));
         $l = gmp_strval(gmp_Utils::gmp_mod2(gmp_mul(gmp_add($three_x2, $a), $inverse), $p));
         $x3 = gmp_strval(gmp_Utils::gmp_mod2(gmp_sub(gmp_pow($l, 2), gmp_mul(2, $p1->x)), $p));
         $y3 = gmp_strval(gmp_Utils::gmp_mod2(gmp_sub(gmp_mul($l, gmp_sub($p1->x, $x3)), $p1->y), $p));
         if (gmp_cmp(0, $y3) > 0) {
             $y3 = gmp_strval(gmp_add($p, $y3));
         }
         $p3 = new Point($p1->curve, $x3, $y3);
         return $p3;
     } elseif (extension_loaded('bcmath') && USE_EXT == 'BCMATH') {
         $p = $p1->curve->getPrime();
         $a = $p1->curve->getA();
         $inverse = NumberTheory::inverse_mod(bcmul(2, $p1->y), $p);
         $three_x2 = bcmul(3, bcpow($p1->x, 2));
         $l = bcmod(bcmul(bcadd($three_x2, $a), $inverse), $p);
         $x3 = bcmod(bcsub(bcpow($l, 2), bcmul(2, $p1->x)), $p);
         $y3 = bcmod(bcsub(bcmul($l, bcsub($p1->x, $x3)), $p1->y), $p);
         if (bccomp(0, $y3) == 1) {
             $y3 = bcadd($p, $y3);
         }
         $p3 = new Point($p1->curve, $x3, $y3);
         return $p3;
     } else {
         throw new ErrorException("Please install BCMATH or GMP");
     }
 }
Example #6
0
 /**
  * Decompress Public Key
  * 
  * Accepts a y_byte, 02 or 03 indicating whether the Y coordinate is
  * odd or even, and $passpoint, which is simply a hexadecimal X coordinate.
  * Using this data, it is possible to deconstruct the original 
  * uncompressed public key.
  *
  * @param $key
  * @return array|bool
  */
 public static function decompress_public_key($key)
 {
     $y_byte = substr($key, 0, 2);
     $x_coordinate = substr($key, 2);
     $x = gmp_strval(gmp_init($x_coordinate, 16), 10);
     $curve = \SECcurve::curve_secp256k1();
     $generator = \SECcurve::generator_secp256k1();
     try {
         $x3 = \NumberTheory::modular_exp($x, 3, $curve->getPrime());
         $y2 = gmp_add($x3, $curve->getB());
         $y0 = \NumberTheory::square_root_mod_prime(gmp_strval($y2, 10), $curve->getPrime());
         if ($y0 == FALSE) {
             return FALSE;
         }
         $y1 = gmp_strval(gmp_sub($curve->getPrime(), $y0), 10);
         $y_coordinate = $y_byte == '02' ? \gmp_Utils::gmp_mod2(gmp_init($y0, 10), 2) == '0' ? $y0 : $y1 : (\gmp_Utils::gmp_mod2(gmp_init($y0, 10), 2) !== '0' ? $y0 : $y1);
         $y_coordinate = str_pad(gmp_strval($y_coordinate, 16), 64, '0', STR_PAD_LEFT);
         $point = new \Point($curve, gmp_strval(gmp_init($x_coordinate, 16), 10), gmp_strval(gmp_init($y_coordinate, 16), 10), $generator->getOrder());
     } catch (\Exception $e) {
         return FALSE;
     }
     return array('x' => $x_coordinate, 'y' => $y_coordinate, 'point' => $point, 'public_key' => '04' . $x_coordinate . $y_coordinate);
 }
Example #7
0
 public function decompress_public_key($key)
 {
     // Initialize
     $y_byte = substr($key, 0, 2);
     $x_coordinate = substr($key, 2);
     // Set variables
     $x = gmp_strval(gmp_init($x_coordinate, 16), 10);
     $curve = SECcurve::curve_secp256k1();
     $generator = SECcurve::generator_secp256k1();
     // Decode
     try {
         $x3 = NumberTheory::modular_exp($x, 3, $curve->getPrime());
         $y2 = gmp_add($x3, $curve->getB());
         $y0 = NumberTheory::square_root_mod_prime(gmp_strval($y2, 10), $curve->getPrime());
         if ($y0 === false) {
             return false;
         }
         $y1 = gmp_strval(gmp_sub($curve->getPrime(), $y0), 10);
         $y_coordinate = $y_byte == '02' ? gmp_Utils::gmp_mod2(gmp_init($y0, 10), 2) == '0' ? $y0 : $y1 : (gmp_Utils::gmp_mod2(gmp_init($y0, 10), 2) !== '0' ? $y0 : $y1);
         $y_coordinate = str_pad(gmp_strval($y_coordinate, 16), 64, '0', STR_PAD_LEFT);
         $point = new Point($curve, gmp_strval(gmp_init($x_coordinate, 16), 10), gmp_strval(gmp_init($y_coordinate, 16), 10), $generator->getOrder());
     } catch (Exception $e) {
         return false;
     }
     // Return
     return array('x' => $x_coordinate, 'y' => $y_coordinate, 'point' => $point, 'public_key' => '04' . $x_coordinate . $y_coordinate);
 }
 public static function is_prime($n)
 {
     if (extension_loaded('gmp') && USE_EXT == 'GMP') {
         return gmp_prob_prime($n);
     } else {
         if (extension_loaded('bcmath') && USE_EXT == 'BCMATH') {
             self::$miller_rabin_test_count = 0;
             $t = 40;
             $k = 0;
             $m = bcsub($n, 1);
             while (bcmod($m, 2) == 0) {
                 $k = bcadd($k, 1);
                 $m = bcdiv($m, 2);
             }
             for ($i = 0; $i < $t; $i++) {
                 $a = bcmath_Utils::bcrand(1, bcsub($n, 1));
                 $b0 = self::modular_exp($a, $m, $n);
                 if ($b0 != 1 && $b0 != bcsub($n, 1)) {
                     $j = 1;
                     while ($j <= $k - 1 && $b0 != bcsub($n, 1)) {
                         $b0 = self::modular_exp($b0, 2, $n);
                         if ($b0 == 1) {
                             self::$miller_rabin_test_count = $i + 1;
                             return false;
                         }
                         $j++;
                     }
                     if ($b0 != bcsub($n, 1)) {
                         self::$miller_rabin_test_count = $i + 1;
                         return false;
                     }
                 }
             }
             return true;
         } else {
             throw new ErrorException("Please install BCMATH or GMP");
         }
     }
 }