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; }
/** * 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); }
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); }