-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wallet): implement wallet generation
- Loading branch information
1 parent
e76e31f
commit f975c1a
Showing
8 changed files
with
208 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace XRPL\Service\Wallet; | ||
|
||
use XRPL\Helper\CryptographyHelper; | ||
|
||
final class AddressService | ||
{ | ||
private const int ADDRESS_PREFIX_ADDRESS = 0; | ||
|
||
public static function deriveAddress(string $publicKey): string | ||
{ | ||
$publicKeyBinary = hex2bin($publicKey); | ||
|
||
$hash256 = hash('sha256', $publicKeyBinary, true); | ||
$hash160 = hash('ripemd160', $hash256, true); | ||
$hexValue = bin2hex($hash160); | ||
|
||
$byteArray = CryptographyHelper::byteStringToArray($hexValue); | ||
$sliced = \array_slice($byteArray, 0, 32); // Not sure this is useful, since byteArray is (always) 20 long | ||
|
||
$addressBytes = array_merge([self::ADDRESS_PREFIX_ADDRESS], $sliced); | ||
|
||
$check = CryptographyHelper::doubleSha256(CryptographyHelper::byteArrayToString($addressBytes)); | ||
$checkBytes = CryptographyHelper::byteStringToArray(bin2hex($check)); | ||
|
||
$checkSum = \array_slice($checkBytes, 0, 4); | ||
$seedBytes = array_merge($addressBytes, $checkSum); | ||
|
||
return CryptographyHelper::encodeBase58(CryptographyHelper::byteArrayToString($seedBytes)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace XRPL\Service\Wallet; | ||
|
||
use Elliptic\EdDSA; | ||
use XRPL\Helper\CryptographyHelper; | ||
use XRPL\ValueObject\KeyPair; | ||
use XRPL\ValueObject\Seed; | ||
use XRPL\ValueObject\Wallet; | ||
|
||
final class KeyPairGenerator | ||
{ | ||
private const string PREFIX_ED25519 = 'ED'; | ||
|
||
public static function generateKeyPair(Seed $seed): KeyPair | ||
{ | ||
$payload = $seed->payload; | ||
|
||
$halfSha512 = strtoupper(bin2hex(CryptographyHelper::halfSha512(CryptographyHelper::byteArrayToString($payload)))); | ||
|
||
$elliptic = new EdDSA(Wallet::ALGORITHM_ED25519); | ||
$rawKeypair = $elliptic->keyFromSecret($halfSha512); | ||
|
||
$privateKey = self::PREFIX_ED25519 . strtoupper($rawKeypair->getSecret('hex')); | ||
$publicKey = self::PREFIX_ED25519 . strtoupper($rawKeypair->getPublic('hex')); | ||
|
||
return new KeyPair($privateKey, $publicKey); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace XRPL\Service\Wallet; | ||
|
||
use XRPL\Helper\CryptographyHelper; | ||
use XRPL\ValueObject\Seed; | ||
use XRPL\ValueObject\Wallet; | ||
|
||
final class Seeder | ||
{ | ||
public const array ED25519_SEED_PREFIX = [1, 225, 75]; | ||
public const array SECP256K1_SEED = [33]; | ||
|
||
public static function generateSeed(): string | ||
{ | ||
$entropy = self::generateEntropy(); | ||
|
||
$seedData = array_merge(self::ED25519_SEED_PREFIX, $entropy); | ||
|
||
$check = CryptographyHelper::doubleSha256(CryptographyHelper::byteArrayToString($seedData)); | ||
$checkBytes = CryptographyHelper::byteStringToArray(bin2hex($check)); | ||
|
||
$checkSum = \array_slice($checkBytes, 0, 4); | ||
$seedBytes = array_merge($seedData, $checkSum); | ||
|
||
$seedString = CryptographyHelper::byteArrayToString($seedBytes); | ||
return CryptographyHelper::encodeBase58($seedString); | ||
} | ||
|
||
private static function generateEntropy(int $length = 16): array | ||
{ | ||
$bytes = bin2hex(random_bytes($length)); | ||
|
||
return CryptographyHelper::byteStringToArray($bytes); | ||
} | ||
|
||
public static function decodeSeed(string $seed): Seed | ||
{ | ||
$clearSeed = CryptographyHelper::decodeBase58($seed); | ||
|
||
$byteArray = CryptographyHelper::byteStringToArray(bin2hex($clearSeed)); | ||
$checkSum = \array_slice($byteArray, -4); | ||
$withoutChecksum = \array_slice($byteArray, 0, -4); | ||
|
||
$versionBytesCount = \count(self::ED25519_SEED_PREFIX); | ||
$prefix = \array_slice($withoutChecksum, 0, $versionBytesCount); | ||
$payload = \array_slice($withoutChecksum, $versionBytesCount); | ||
|
||
if (\count($payload) !== 16) { | ||
throw new \Exception('Invalid seed length'); | ||
} | ||
|
||
return new Seed( | ||
Wallet::ALGORITHM_ED25519, | ||
$prefix, | ||
$payload, | ||
$checkSum, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace XRPL\Service\Wallet; | ||
|
||
use XRPL\ValueObject\Wallet; | ||
|
||
final class WalletGenerator | ||
{ | ||
public static function generate(): Wallet | ||
{ | ||
$seed = Seeder::generateSeed(); | ||
|
||
return self::generateFromSeed($seed); | ||
} | ||
|
||
public static function generateFromSeed(string $seed): Wallet | ||
{ | ||
$seed = Seeder::decodeSeed($seed); | ||
$keyPair = KeyPairGenerator::generateKeyPair($seed); | ||
|
||
return new Wallet($seed, $keyPair, AddressService::deriveAddress($keyPair->publicKey)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace XRPL\ValueObject; | ||
|
||
final readonly class Seed | ||
{ | ||
public function __construct( | ||
public string $algorithm, | ||
public array $prefix, | ||
public array $payload, | ||
public array $checksum, | ||
) { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters