PHP bindings for https://github.com/bitcoin/secp256k1
Please note that the upstream library, [libsecp256k1] is considered experimental by it's authors, and has not yet been formally released. For this reason, it's use should be discouraged. For consensus systems this warning is critical.
Only PHP 5.x is supported at the moment - PHP7 will come soon.
- Runs against latest libsecp256k1 (until upstream produces versioned releases)
- Tests are present for all currently added functions. The C library also has it's own tests, with some useful edge case tests, which will be ported soon.
- This extension only supports deterministic signatures at present. In fact, no RNG is utilized in this extension - private keys must be generated elsewhere.
- The extension exposes the same raw API of libsecp256k1. As such, you must ensure you are passing the binary representations of each value.
- In keeping with libsecp256k1, this extension returns certain data to the user by writing to a variable reference, and returning a code indicating the failure/success.
git clone [email protected]:Bit-Wasp/secp256k1-php
git clone [email protected]:bitcoin/secp256k1
cd secp256k1
./autogen.sh && ./configure --enable-module-recovery && make && sudo make install
cd ../secp256k1-php/secp256k1
phpize && ./configure --with-secp256k1 && make && sudo make install
If you're a heavy user, you can add this line to your php.ini files for php-cli, apache2, or php-fpm.
extension=secp256k1.so
time php -dextension=secp256k1.so ../benchmark.php > /dev/null
Yes - it is FAST!
php -dextension=secp256k1.so vendor/bin/phpunit tests/
secp256k1_pubkey_create(string $privateKey32, integer $compressKey, string & $publicKey)
takes $privateKey32
,
and writes the public key to $publicKey
. Depending on whether $compressKey
is 0 or 1, the public key will be
uncompressed or compressed respectively.
// Private keys are never generated by secp256k1.
$privateKey = pack("H*", "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789");
$publicKey = '';
$compressKey = false;
$result = secp256k1_ec_pubkey_create($privateKey, $compressKey, $publicKey);
if ($result === 1) {
echo sprintf("Public key is: %s\nIt %s compressed", bin2hex($publicKey), $compressKey ? 'was' : 'was not') . "\n";
} else {
throw new \Exception('secp256k1_pubkey_create: secret key was invalid');
}
secp256k1_ec_pubkey_decompress(string & $publicKey)
takes a compressed public key (33 bytes, beginning with
\x02 or \x03) and sets the uncompressed key to$publicKey
if the operation succeeds.
// A compressed public key starts with 02/03. Compressed keys can be created from secp256k1_pubkey_create
$publicKey = pack("H*", "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd");
// $publicKey gets modified by this function!
$result = secp256k1_ec_pubkey_decompress($publicKey);
if ($result == 1) {
echo sprintf("Decompressed key is %s\n", bin2hex($publicKey));
// should be 04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235
} else {
throw new \Exception('secp256k1_ec_pubkey_decompress: public key was invalid');
}
secp256k1_seckey_verify(string $privateKey)
validate the given `$privateKey¬ and returns 0 or 1 as the result.
// A compressed public key starts with 02/03. Compressed keys can be created from secp256k1_pubkey_create
$publicKey = pack("H*", "a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd");
$result = secp256k1_ec_seckey_verify($publicKey);
if ($result == 1) {
echo "Private key was valid\n";
} else {
throw new \Exception("Private key was invalid");
}
secp256k1_pubkey_verify(string $publicKey)
validates the given $publicKey
, and returns 0 or 1 as the result.
// A compressed public key starts with 02/03. Compressed keys can be created from secp256k1_pubkey_create
$publicKey = pack("H*", "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd");
$result = secp256k1_ec_pubkey_verify($publicKey);
if ($result == 1) {
echo "Public key was valid\n";
} else {
throw new \Exception("Public key was invalid");
}
secp256k1_ec_privkey_tweak_add(string & $privateKey32, string $tweak32)
takes the given $tweak
value and adds it to the private key.
The result is written to the provided $privateKey
memory location.
This function is useful for deterministic key derivation.
$privateKey = pack("H*", "88b59280e39997e49ebd47ecc9e3850faff5d7df1e2a22248c136cbdd0d60aae");
$tweak = pack("H*", "0000000000000000000000000000000000000000000000000000000000000001");
$result = secp256k1_ec_privkey_tweak_add($privateKey, $tweak);
if ($result == 1) {
echo sprintf("Tweaked private key: %s\n", bin2hex($privateKey));
} else {
throw new \Exception("Invalid private key or augend value");
}
secp256k1_ec_pubkey_tweak_add(string & $publicKey, string $tweak32)
takes the given $tweak
value, converts it to a point, and
adds the point to the $publicKey
point. The result is written to the provided $publicKey memory location.
This function is useful for deterministic key derivation.
$publicKey = hex2bin("03fae8f5e64c9997749ef65c5db9f0ec3e121dc6901096c30da0f105a13212b6db");
$tweak = pack("H*", "0000000000000000000000000000000000000000000000000000000000000001");
$result = secp256k1_ec_pubkey_tweak_add($publicKey, $tweak);
if ($result == 1) {
echo sprintf("Tweaked public key: %s\n", bin2hex($publicKey));
} else {
throw new \Exception("Invalid public key or augend value");
}
secp256k1_ec_pubkey_tweak_mul(string & $publicKey, integer $publicKeyLen, string $tweak32)
takes the given $tweak
value, and
performs scalar multiplication of against the provided $publicKey
point. Note - the length of the supplied public key must be supplied.
$publicKey = pack("H*", "03fae8f5e64c9997749ef65c5db9f0ec3e121dc6901096c30da0f105a13212b6db");
$tweak = pack("H*", "0000000000000000000000000000000000000000000000000000000000000002");
$result = secp256k1_ec_pubkey_tweak_mul($publicKey, strlen($publicKey), $tweak);
if ($result == 1) {
echo sprintf("Tweaked public key: %s\n", bin2hex($publicKey));
} else {
throw new \Exception("Invalid public key or multiplicand value");
}
secp256k1_ecdsa_sign(string $msg32, string $privateKey, string & $signature)
takes the given $msg32
and signs it with
$privateKey
. If successful, the signature is written to the memory location of $signature
.
$msg32 = hash('sha256', 'this is a message!', true);
$publicKey = pack("H*", "88b59280e39997e49ebd47ecc9e3850faff5d7df1e2a22248c136cbdd0d60aae");
$signature = '';
$result = secp256k1_ecdsa_sign($msg32, $privateKey, $signature);
if ($result == 1) {
echo sprintf("Produced signature: %s \n", bin2hex($signature));
} else {
throw new \Exception("Failed to create signature");
}
secp256k1_ecdsa_verify(string $msg32, string $signature, string $publicKey)
verifies the provided $msg32
and $signature
against the provided $publicKey
. Returns for valid signature, 0 for incorrect signature, -1 for an invalid public key, -2 for an invalid signature.
$msg32 = hash('sha256', 'this is a message!', true);
$signature = hex2bin("3044022055ef6953afd139d917d947ba7823ab5dfb9239ba8a26295a218cad88fb7299ef022057147cf4233ff3b87fa64d82a0b9a327e9b6d5d0070ab3f671b795934c4f2074");
$publicKey = hex2bin('04fae8f5e64c9997749ef65c5db9f0ec3e121dc6901096c30da0f105a13212b6db4315e65a2d63cc667c034fac05cdb3c7bc1abfc2ad90f7f97321613f901758c9');
$result = secp256k1_ecdsa_verify($msg32, $signature, $publicKey);
if ($result == 1) {
echo "Signature was verified\n";
} else {
echo "Signature was NOT VERIFIED\n";
}