Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 188 additions & 26 deletions utils/vanitygen.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
<?php

/**
* PHPCoin Vanity Address Generator
*
* This script generates a PHPCoin address with a custom prefix.
* It is self-contained and does not require any external dependencies.
*
* Usage: php vanitygen.php <prefix> [-c] [-d]
* - <prefix>: The desired prefix for the PHPCoin address.
* - -c: Case-sensitive matching.
* - -d: Enable debug output.
*/

const VANITYGEN_NAME = 'PHPCoin Vanity Address Generator';
const VANITYGEN_VERSION = '0.0.1';
const VANITYGEN_VERSION = '0.0.2';
const VANITYGEN_USAGE = 'Usage: php vanitygen.php prefix [-c] [-d]' . PHP_EOL .
' prefix Prefix for the PHPCoin address (e.g., "Php")' . PHP_EOL .
' -c Case sensitive matching' . PHP_EOL .
' -d Enable debug output' . PHP_EOL;
const VANITYGEN_URL = 'https://github.com/phpcoinn/node/blob/main/utils/vanitygen.php';
const DEFAULT_CHAIN_ID = '00';
const VANITYGEN_URL = 'https://github.com/phpcoinn/node/blob/main/utils/vanitygen.php';
const CHAIN_PREFIX = "38";

$debug = false;

print VANITYGEN_NAME . ' v' . VANITYGEN_VERSION . PHP_EOL;
if (php_sapi_name() !== 'cli') {
exit('ERROR: This script must be run from the command line' . PHP_EOL);
};

setupOrExit();
print VANITYGEN_NAME . ' v' . VANITYGEN_VERSION . PHP_EOL;

generateVanityAddress(getOptionsOrExit($argv));

print PHP_EOL . 'Exiting ' . VANITYGEN_NAME . PHP_EOL;

//
// Script Functions
//

/**
* Generates a vanity PHPCoin address based on the provided options.
*
Expand Down Expand Up @@ -47,7 +65,7 @@ function generateVanityAddress(array $options): array
$count = 0;

while (true) {
$account = Account::generateAcccount();
$account = generateAccount();
$address = $account['address'];
$count++;
_debug('Generation '. $count . ': ' . $address);
Expand Down Expand Up @@ -136,26 +154,6 @@ function getOptionsOrExit(array $argv): array
];
}

/**
* Sets up the environment or exits if conditions are not met.
*
* Ensures the script is run from the command line and that the autoload file exists.
*/
function setupOrExit(): void
{
if (php_sapi_name() !== 'cli') {
exit('ERROR: This script must be run from the command line' . PHP_EOL);
};
$autoload = Phar::running()
? 'vendor/autoload.php'
: dirname(__DIR__) . '/vendor/autoload.php';

if (! file_exists($autoload)) {
exit('ERROR: Autoload file not found. Please run "composer install".' . PHP_EOL);
}
require_once $autoload;
}

/**
* Outputs debug messages if debugging is enabled.
*
Expand All @@ -168,3 +166,167 @@ function _debug(string $message): void
print '[DEBUG] ' . $message . PHP_EOL;
}
}

//
// Crypto Functions
//

//
// Source: include/class/Account.php
//
function generateAccount()
{
// using secp256k1 curve for ECDSA
$args = [
"curve_name" => "secp256k1",
"private_key_type" => OPENSSL_KEYTYPE_EC,
];

// generates a new key pair
$key1 = openssl_pkey_new($args);

// exports the private key encoded as PEM
openssl_pkey_export($key1, $pvkey);

if(PHP_VERSION_ID > 80000) {
$in = sys_get_temp_dir() . "/phpcoin.in.pem";
$out = sys_get_temp_dir() . "/phpcoin.out.pem";
file_put_contents($in, $pvkey);
$cmd = "openssl ec -in $in -out $out >/dev/null 2>&1";
shell_exec($cmd);
$pvkey = file_get_contents($out);
unlink($in);
unlink($out);
}

// converts the PEM to a base58 format
$private_key = pem2coin($pvkey);

// exports the private key encoded as PEM
$pub = openssl_pkey_get_details($key1);

// converts the PEM to a base58 format
$public_key = pem2coin($pub['key']);

// generates the account's address based on the public key
$address = getAddress($public_key);
return ["address" => $address, "public_key" => $public_key, "private_key" => $private_key];
}

function getAddress($public_key) {
if(empty($public_key)) return null;
$hash1=hash('sha256', $public_key);
$hash2=hash('ripemd160',$hash1);
$baseAddress=CHAIN_PREFIX.$hash2;
$checksumCalc1=hash('sha256', $baseAddress);
$checksumCalc2=hash('sha256', $checksumCalc1);
$checksumCalc3=hash('sha256', $checksumCalc2);
$checksum=substr($checksumCalc3, 0, 8);
$addressHex = $baseAddress.$checksum;
$address = base58_encode(hex2bin($addressHex));
return $address;
}

//
// Source: include/functions.inc.php
//
function pem2coin($data)
{
$data = str_replace("-----BEGIN PUBLIC KEY-----", "", $data);
$data = str_replace("-----END PUBLIC KEY-----", "", $data);
$data = str_replace("-----BEGIN EC PRIVATE KEY-----", "", $data);
$data = str_replace("-----END EC PRIVATE KEY-----", "", $data);
$data = str_replace("\n", "", $data);
$data = base64_decode($data);
return base58_encode($data);
}

//
// Source: include/common.functions.php
// Base58 encoding/decoding functions - all credits go to https://github.com/stephen-hill/base58php
//
function base58_encode($string)
{
$alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
$base = strlen($alphabet);
// Type validation
if (is_string($string) === false) {
return false;
}
// If the string is empty, then the encoded string is obviously empty
if (strlen($string) === 0) {
return '';
}
// Now we need to convert the byte array into an arbitrary-precision decimal
// We basically do this by performing a base256 to base10 conversion
$hex = unpack('H*', $string);
$hex = reset($hex);
$decimal = gmp_init($hex, 16);
// This loop now performs base 10 to base 58 conversion
// The remainder or modulo on each loop becomes a base 58 character
$output = '';
while (gmp_cmp($decimal, $base) >= 0) {
list($decimal, $mod) = gmp_div_qr($decimal, $base);
$output .= $alphabet[gmp_intval($mod)];
}
// If there's still a remainder, append it
if (gmp_cmp($decimal, 0) > 0) {
$output .= $alphabet[gmp_intval($decimal)];
}
// Now we need to reverse the encoded data
$output = strrev($output);
// Now we need to add leading zeros
$bytes = str_split($string);
foreach ($bytes as $byte) {
if ($byte === "\x00") {
$output = $alphabet[0].$output;
continue;
}
break;
}
return (string)$output;
}

function base58_decode($base58)
{
$alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
$base = strlen($alphabet);

// Type Validation
if (is_string($base58) === false) {
return false;
}
// If the string is empty, then the decoded string is obviously empty
if (strlen($base58) === 0) {
return '';
}
$indexes = array_flip(str_split($alphabet));
$chars = str_split($base58);
// Check for invalid characters in the supplied base58 string
foreach ($chars as $char) {
if (isset($indexes[$char]) === false) {
return false;
}
}
// Convert from base58 to base10
$decimal = gmp_init($indexes[$chars[0]], 10);
for ($i = 1, $l = count($chars); $i < $l; $i++) {
$decimal = gmp_mul($decimal, $base);
$decimal = gmp_add($decimal, $indexes[$chars[$i]]);
}
// Convert from base10 to base256 (8-bit byte array)
$output = '';
while (gmp_cmp($decimal, 0) > 0) {
list($decimal, $byte) = gmp_div_qr($decimal, 256);
$output = pack('C', gmp_intval($byte)).$output;
}
// Now we need to add leading zeros
foreach ($chars as $char) {
if ($indexes[$char] === 0) {
$output = "\x00".$output;
continue;
}
break;
}
return $output;
}