Skip to content

Instantly share code, notes, and snippets.

@afk11
Created May 23, 2014 01:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afk11/a3f1174f30e1e8d9ed2d to your computer and use it in GitHub Desktop.
Save afk11/a3f1174f30e1e8d9ed2d to your computer and use it in GitHub Desktop.
Decompress bitcoin public keys (PHP)
// Decompressing a compressed bitcoin public key.
// Will require a big number library, with functions for modular exponent, square root (mod prime), and modulus.
// Requires gmp, and mathyass danters ecclib
public static function decompress_public_key($key)
{
$y_byte = substr($key, 0, 2);
$x_coordinate = substr($key, 2);
// Convert x hexadecimal to a decimal
$x = gmp_strval(gmp_init($x_coordinate, 16),10);
$curve = \SECcurve::curve_secp256k1();
$generator = \SECcurve::generator_secp256k1();
try
{
// x^3 % p
$x3 = \NumberTheory::modular_exp( $x, 3, $curve->getPrime() );
// y^2 = x^3 + b
$y2 = gmp_add(
$x3,
$curve->getB()
);
// Solve for y:
// y = (x^3 + b)^(1/2) % p
$y0 = \NumberTheory::square_root_mod_prime(
gmp_strval($y2, 10),
$curve->getPrime()
);
// Could be another y. Prefix specifies if value is even or odd.
// y' = p - y
$y1 = gmp_strval(gmp_sub($curve->getPrime(), $y0), 10);
// if prefix is 02:
// if y%2 == 0:
// real_y = y
// else
// real_y = y'
// if prefix is 03:
// if y%2 !== 0:
// real_y = y
// else
// real_y = y'
$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);
// Convert the y coordinate to hex, and pad it to 64 characters.
$y_coordinate = str_pad(gmp_strval($y_coordinate, 16),64,'0',STR_PAD_LEFT);
// Instantiate a point based on curve, x coordinate, y coordinate, and order of the curve.. To test that the decompressed point is valid.
$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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment