A collection of common utilities and libraries in PHP for use with Bitcoin and Zetacoin compatable crypto currencies ustilizing the secp256k1 ECDSA curve. It's written in pure PHP and does not require any RPC calls to a Zetacoin client/server
Requirements
The current implementation requires the php5-gmp extension. Future version will automaticly detect and switch between GMP and BCMATH
- PHP 5.3.x or later
- PHP GMP Extension
- PHP OpenSSL Extension
This is still a work in progress but some basic core functions are complete. The code may be messy and all over the place while I'm still pulling things together and I merge this code base with items from the PHPECC codebase.
The current features include:
- Private Key Generation and Loading
- Public Address Print Out
- Message Signing and Verification
- Address Generation and Validation
- Address compression, de-compression, encoding, and decoding.
- Supports Arbitrary Address Prefixes
The following classes are (nearly) fully working
- Base58.class.php
- SECp256k1.class.php
- PointMathGMP.class.php
- AddressValidation.class.php
- AddressCodec.class.php
- PrivateKey.class.php
- Signature.class.php
- Wallet.class.php (partial)
Some planned features include (no ETA):
- Transaction Generation
- Transaction Signing
Usage
PrivateKey
This provides the fundamental function of generating or importing a private key (in Hexadecimal format), then deriving a corresponding public key using the SECp256k1 ECDSA curve. A private key is nothing more than a unique (and extremely large) random number. It's the public key that is really special.
Include the following classes at the top of your PHP code:
include 'SECp256k1.class.php';
include 'PointMathGMP.class.php';
include 'PrivateKey.class.php';
Generate a new private key:
$private = new PrivateKey();
One thing to note is that the generated numbers may not be perfectly secure when done with PHP. For this reason you should import your own private key that you generate using a more random and secure method.
$private = new PrivateKey('1234567890abcdefNOTAREALKEY23456789012345678789');
You can now derive the corresponding X and Y point for the public key
$point = $private->getPubKeyPoints();
That will return an associative array, 'x' and 'y' with a hexadecimal version of your public key point. However, that's not very useful on it's own. Using the AddressCodec class you can convert this point into something more interesting.
AddressCodec
The AddressCodec class provides a simple interface for common Zetacoin/Bitcoin (and compatible) address functions. Load the following classes in your PHP code:
include 'Base58.class.php';
include 'PointMathGMP.class.php';
include 'AddressCodec.class.php';
Converting the public key point into a common crypto currency address is a 3 step process. We'll assume you want to use the modern 'compressed' format.
First, compress your point into a DER format public key
$derPublicKey=AddressCodec::Compress($point);
Second, hash this public key down to a smaller more convenient size:
$hash=AddressCodec::Hash($derPublicKey);
Finally, encode it into the Zetacoin/Bitcoin (or other Altcoin) format.
$bitcoinAddress = AddressCodec::Encode($hash);
$zetacoinAddress = AddressCodec::Encode($hash, "50");
You pass the Hexadecimal version of the address prefix as the second parameter. The result would be the well known crypto currency address:
1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV
ZS67wSwchNQFuTt3abnK4HjpjQ2x79YZed
Other basic functions include the ability to get the X and Y coordinates of a DER Encoded public key that is derived from a private key. Example:
$derPublicKey = '04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235';
$point = AddressCodec::Point($derPublicKey);
echo $point['x'];
echo $point['y'];
That will return an array with both X and Y:
X = a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd
Y = 5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235
Also works with the new compressed public keys used by modern crypto currencies:
$compressedPublicKey = '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd';
$point = AddressCodec::Decompress($compressedPublicKey);
echo $point['x'];
echo $point['y'];
The other way around as demonstrated earlier
$compressedPublicKey = AddressCodec::Compress($point);
$derPublicKey = AddressCodec::Hex($point);
One thing to note is that it is impossible to recover the public key point from a hashed and encoded public key, or even reverse the hashing function applied to a DER public key.
Wallet
Here is were the real fun stuff begins. The Wallet class provides a simple interface to common Zetacoin/Bitcoin (and compatible) functions. At the moment, the wallet can load a private key, display it's associated receive address, and of course, message signing/verification!
To use this, load the following classes in your PHP code:
include 'Base58.class.php';
include 'SECp256k1.class.php';
include 'PointMathGMP.class.php';
include 'PrivateKey.class.php';
include 'Signature.class.php';
include 'AddressCodec.class.php';
include 'Wallet.class.php';
Import or generate a PrivateKey
$private = new PrivateKey('1234567890abcdefNOTAREALKEY23456789012345678789');
# Or
$private = new PrivateKey();
Load this PrivateKey into the Wallet. Optionally set the network prefix (aka address version/prefix) as a HEX, and network name.
$wallet = new Wallet($private);
# Setting "Z" for "ZetaCoin" Address version is 80 in decimal. '50' in HEX.
$wallet->setNetworkPrefix("50");
$wallet->setNetworkName("Zetacoin");
In a single step, print out your receive address:
echo $wallet->getAddress();
Sign a message
echo $message = $wallet->signMessage("Test 1234");
That spits out a signed message in the Satoshi client's standard message signature format:
-----BEGIN ZETACOIN SIGNED MESSAGE-----
Test 1234
-----BEGIN SIGNATURE-----
ZJFVhALJwWV1uz8m1YoXXyvNqFMu4h7A94
H7wVT/QJEd3xIonGorLsDxXHg8DE5byo9fcD5h/LHH02KX7nFKjyvH7AE7PjioCQid4qKOjuMh430G37gKIupDc=
-----END ZETACOIN SIGNED MESSAGE-----
Yes! You can verify a signed message!! A PrivateKey is not required when you only need to verify signed messages.
$message = PHP_EOL;
$message .= "-----BEGIN ZETACOIN SIGNED MESSAGE-----" . PHP_EOL;
$message .= "Test 1234" . PHP_EOL;
$message .= "-----BEGIN SIGNATURE-----" . PHP_EOL;
$message .= "ZJFVhALJwWV1uz8m1YoXXyvNqFMu4h7A94" . PHP_EOL;
$message .= "H7wVT/QJEd3xIonGorLsDxXHg8DE5byo9fcD5h/LHH02KX7nFKjyvH7AE7PjioCQid4qKOjuMh430G37gKIupDc=" . PHP_EOL;
$message .= "-----END ZETACOIN SIGNED MESSAGE-----";
$wallet = new Wallet();
$wallet->setNetworkPrefix("50");
$wallet->setNetworkName("Zetacoin");
echo $wallet->checkSignatureForRawMessage($message) ? 'Verifies' : 'Fails';
Note that the line endings are important since the parser is quite picky at the moment This will be fixed in a later release.
Yes, it's pure PHP!
If you don't want to bother with line endings, you can feed the components in manually:
$message = "Test 1234";
$address = "ZJFVhALJwWV1uz8m1YoXXyvNqFMu4h7A94";
$signature = "H7wVT/QJEd3xIonGorLsDxXHg8DE5byo9fcD5h/LHH02KX7nFKjyvH7AE7PjioCQid4qKOjuMh430G37gKIupDc=";
$wallet = new Wallet();
$wallet->setNetworkPrefix("50");
$wallet->setNetworkName("Zetacoin");
echo $wallet->checkSignatureForMessage($address, $signature, $message) ? 'Verifies' : 'Fails';
Warning!: Pay close attention to the currency's "Network Name" as this affects internal operations that are dependent on it. For example, message signing and verification uses the network name to automatically determine the magic message prefix. If the character case or name deviates from the 'official' implementation, your signatures will fail.
If necessary you can override the automatically generated prefix by using the "setMessageMagic()" function in the Wallet class.
$wallet->setMessageMagic("\x19 Zetacoin Signed Message:\n");
To return to the default automatically generated version, pass 'null' as the parameter:
$wallet->setMessageMagic(null);
Where to get it
The library can be download from my Github repository: https://github.com/tuaris/CryptoCurrencyPHP
If you find this useful, please send me some
Bitcoin: 1B6eyXVRPxdEitW5vWrUnzzXUy6o38P9wN
Zetacoin: ZK6kdE5H5q7H6QRNRAuqLF6RrVD4cFbiNX