Skip to content

Bablakeluke/secp256k1-php

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

secp256k1-php

Build Status Join the chat at https://gitter.im/Bit-Wasp/secp256k1-php

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.

Requirements

Only PHP 5.x is supported at the moment - PHP7 will come soon.

About the extension

  • 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.

To Install:

    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

(Optional) - Enable extension by default!

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

Run Benchmarks

    time php -dextension=secp256k1.so ../benchmark.php > /dev/null

Yes - it is FAST!

Run Tests

    php -dextension=secp256k1.so vendor/bin/phpunit tests/

Examples

Convert a private key to a public key.

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');
}

Compress a public key

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');
}

Verify a private key

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");
}

Verify a public key

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");
}

Private Key tweak by addition

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");
}

Public Key tweak by addition

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");
}

Public Key tweak by multiplication

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");
}

Sign a message

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");
}

Verify a 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";
}

About

PHP bindings for bitcoin/secp256k1

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • PHP 52.2%
  • C 47.8%