diff --git a/TestWallet.php b/TestWallet.php new file mode 100644 index 0000000..d45717f --- /dev/null +++ b/TestWallet.php @@ -0,0 +1,27 @@ +getAddress()."\n"; +echo 'public_key: ' . $keyPair->getPublicKey()."\n"; +echo 'private_key: ' . $keyPair->getPrivateKey()."\n"; +echo 'mnemonic: ' . $mnemonic."\n"; + + +echo "\n\nSanity Check: "; +$mnemonic = "profit business cause evoke onion speed bean economy nephew edit balcony trophy"; +$keyPair = KeyPair::fromMnemonic($mnemonic, ''); +$address = $keyPair->getAddress(); +echo 'address: ' . $address."\n"; +echo 'public_key: ' . $keyPair->getPublicKey() . "\n"; +echo 'private_key: ' . $keyPair->getPrivateKey() . "\n"; +echo 'mnemonic: ' . $mnemonic . "\n"; diff --git a/composer.json b/composer.json index a935f54..569c02b 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,10 @@ "ext-mbstring": "*", "ext-openssl": "*", "ext-pdo": "*", + "ext-gmp": "*", + "ext-bcmath": "*", "guzzlehttp/guzzle": "^7.5", + "kornrunner/secp256k1": "^0.3.0", "kornrunner/keccak": "^1.1", "monolog/monolog": "^3.0", "stephenhill/base58": "^1.1", diff --git a/core/Cryptography/KeyPair.php b/core/Cryptography/KeyPair.php index 3382005..0aeb9ac 100644 --- a/core/Cryptography/KeyPair.php +++ b/core/Cryptography/KeyPair.php @@ -3,7 +3,9 @@ namespace Blockchain\Core\Cryptography; +use Blockchain\Wallet\HDWallet; use Exception; +use kornrunner\Keccak; /** * Cryptographic Key Pair @@ -12,274 +14,190 @@ */ class KeyPair { - private string $privateKey; - private string $publicKey; - private string $address; - - public function __construct(string $privateKey, string $publicKey, string $address) - { - $this->privateKey = $privateKey; - $this->publicKey = $publicKey; - $this->address = $address; - } - /** - * Generate new key pair + * @var string The private key in hexadecimal format */ - public static function generate(): self - { - // Generate private key (32 bytes) - $privateKey = random_bytes(32); - $privateKeyHex = bin2hex($privateKey); - - // Generate public key using secp256k1 curve - $publicKeyHex = self::generatePublicKeyHex($privateKeyHex); - - // Generate address from public key - $address = self::generateAddressFromHex($publicKeyHex); - - return new self($privateKeyHex, $publicKeyHex, $address); - } - + private string $privateKey; + /** - * Create key pair from private key + * @var string The compressed public key in hexadecimal format */ - public static function fromPrivateKey(string $privateKeyHex): self - { - $privateKey = hex2bin($privateKeyHex); - - if (strlen($privateKey) !== 32) { - throw new Exception("Invalid private key length"); - } - - $publicKeyHex = self::generatePublicKeyHex($privateKeyHex); - $address = self::generateAddressFromHex($publicKeyHex); - - return new self($privateKeyHex, $publicKeyHex, $address); - } - + private string $publicKey; + /** - * Create key pair from mnemonic phrase + * @var string The Ethereum-compatible address derived from the public key */ - public static function fromMnemonic(array $mnemonic, string $passphrase = ''): self - { - try { - error_log("KeyPair::fromMnemonic - Starting with " . count($mnemonic) . " words"); - error_log("KeyPair::fromMnemonic - Words: " . implode(' ', $mnemonic)); - - $seed = Mnemonic::toSeed($mnemonic, $passphrase); - error_log("KeyPair::fromMnemonic - Seed generated, length: " . strlen($seed)); - - $privateKeyHex = substr($seed, 0, 64); - error_log("KeyPair::fromMnemonic - Private key hex: " . $privateKeyHex); - - return self::fromPrivateKey($privateKeyHex); - } catch (Exception $e) { - error_log("KeyPair::fromMnemonic - Error: " . $e->getMessage()); - throw $e; - } - } - + private string $address; + /** - * Generate public key hex from private key hex using secp256k1 + * KeyPair constructor. + * + * @param string $priv Private key in hex + * @param string $pub Public key in hex (compressed) + * @param string $addr Ethereum-style address (0x-prefixed) */ - private static function generatePublicKeyHex(string $privateKeyHex): string + public function __construct(string $priv, string $pub, string $addr) { - // Generate public key using elliptic curve cryptography - $publicKeyPoint = EllipticCurve::generatePublicKey($privateKeyHex); - - // Compress the public key and return as hex string - return EllipticCurve::compressPublicKey($publicKeyPoint); + $this->privateKey = $priv; + $this->publicKey = $pub; + $this->address = $addr; } - - /** - * Generate public key from private key using secp256k1 (legacy method) - */ - private static function generatePublicKey(string $privateKey): string - { - $privateKeyHex = bin2hex($privateKey); - - // Generate public key using elliptic curve cryptography - $publicKeyPoint = EllipticCurve::generatePublicKey($privateKeyHex); - - // Compress the public key - $compressedPublicKey = EllipticCurve::compressPublicKey($publicKeyPoint); - - return hex2bin($compressedPublicKey); } /** - * Generate address from public key hex using Keccak-256 (Ethereum-style) + * Generate a new random key pair. + * + * @return self + * @throws Exception If random_bytes fails */ - private static function generateAddressFromHex(string $publicKeyHex): string + public static function generate(): self { - // For compressed public key, decompress first - if (strlen($publicKeyHex) === 66) { // Compressed public key - $publicKeyPoint = EllipticCurve::decompressPublicKey($publicKeyHex); - $uncompressedKey = '04' . str_pad($publicKeyPoint['x'], 64, '0', STR_PAD_LEFT) . - str_pad($publicKeyPoint['y'], 64, '0', STR_PAD_LEFT); - } else { - $uncompressedKey = $publicKeyHex; - } - - // Remove '04' prefix if present - if (substr($uncompressedKey, 0, 2) === '04') { - $uncompressedKey = substr($uncompressedKey, 2); - } - - // Calculate Keccak-256 hash (fallback using SHA-256) - $hash = hash('sha256', hex2bin($uncompressedKey)); - - // Take last 20 bytes (40 hex characters) as address - $address = substr($hash, -40); - - return '0x' . $address; + $privHex = bin2hex(random_bytes(32)); + return self::fromPrivateKey($privHex); } /** - * Generate address from public key using Keccak-256 (Ethereum-style) + * Derive a key pair from a BIP-39 mnemonic and optional passphrase. + * + * @param string $mnemonic Space-separated mnemonic phrase + * @param string $passphrase Optional passphrase for seed derivation + * @return self + * @throws Exception If private key derivation fails */ - private static function generateAddress(string $publicKey): string + public static function fromMnemonic(string $mnemonic, string $passphrase = ''): self { - // For compressed public key, decompress first - $publicKeyHex = bin2hex($publicKey); - - if (strlen($publicKeyHex) === 66) { // Compressed public key - $publicKeyPoint = EllipticCurve::decompressPublicKey($publicKeyHex); - $uncompressedKey = '04' . str_pad($publicKeyPoint['x'], 64, '0', STR_PAD_LEFT) . - str_pad($publicKeyPoint['y'], 64, '0', STR_PAD_LEFT); - } else { - $uncompressedKey = $publicKeyHex; - } - - // Remove '04' prefix if present - if (substr($uncompressedKey, 0, 2) === '04') { - $uncompressedKey = substr($uncompressedKey, 2); - } - - // Calculate Keccak-256 hash - $hash = self::keccak256(hex2bin($uncompressedKey)); - - // Take last 20 bytes and add 0x prefix - $address = '0x' . substr($hash, -40); - - return $address; + $privHex = HDWallet::derivePrivateKeyFromMnemonic($mnemonic, $passphrase); + return self::fromPrivateKey($privHex); } - + /** - * Keccak-256 hash function + * Derive the full key pair and address from a private key. + * + * @param string $privHex Private key in hexadecimal format + * @return self + * @throws Exception If the private key is invalid or processing fails */ - private static function keccak256(string $data): string + public static function fromPrivateKey(string $privHex): self { - // Simple implementation - in production use a proper Keccak library - $hash = hash('sha3-256', $data); - return $hash; + $privBin = hex2bin($privHex); + if ($privBin === false || strlen($privBin) !== 32) { + throw new Exception("Invalid private key"); + } + + $pt = self::generatePublicKey($privHex); + $pubHex = self::compressPublicKey($pt); + $rawXY = hex2bin($pt['x'] . $pt['y']); + $hash = Keccak::hash($rawXY, 256); + $addr = '0x' . substr($hash, -40); + + return new self($privHex, $pubHex, $addr); } - + /** - * Get private key + * Get the private key. + * + * @return string Private key in hex */ public function getPrivateKey(): string { return $this->privateKey; } - + /** - * Get public key + * Get the compressed public key. + * + * @return string Public key in hex */ public function getPublicKey(): string { return $this->publicKey; } - + /** - * Get address + * Get the Ethereum-compatible address. + * + * @return string Address in 0x-prefixed hex format */ public function getAddress(): string { return $this->address; } - + /** - * Generate mnemonic phrase + * Generate a public key (x and y coordinates) from a private key. + * + * @param string $privateKeyHex Private key in hexadecimal format + * @return array{x: string, y: string} Associative array of x and y coordinates in hex + * @throws Exception If OpenSSL fails to parse or extract coordinates */ - public function getMnemonic(): string + public static function generatePublicKey(string $privateKeyHex): array { - // DEPRECATED: This method is deprecated and should not be used for new wallets. - // It generates a deterministic mnemonic from private key which may contain duplicates. - // Use Mnemonic::generate() for new wallets instead. - - error_log("WARNING: KeyPair::getMnemonic() is deprecated and may generate invalid mnemonics. Use Mnemonic::generate() instead."); - - // Generate a proper mnemonic using the correct BIP39 implementation - try { - $mnemonic = Mnemonic::generate(12); - return implode(' ', $mnemonic); - } catch (Exception $e) { - error_log("Failed to generate mnemonic: " . $e->getMessage()); - - // Fallback to old method (with warnings) - return $this->getLegacyMnemonic(); + $privateKeyBin = hex2bin($privateKeyHex); + if ($privateKeyBin === false || strlen($privateKeyBin) !== 32) { + throw new Exception("Invalid private key"); } + + $pem = self::buildECPrivateKeyPEM($privateKeyHex); + $key = openssl_pkey_get_private($pem); + + if (!$key) { + throw new Exception("Failed to parse EC private key from PEM"); + } + + $details = openssl_pkey_get_details($key); + if (!isset($details['ec']['x'], $details['ec']['y'])) { + throw new Exception("Failed to extract public key coordinates"); + } + + return [ + 'x' => bin2hex($details['ec']['x']), + 'y' => bin2hex($details['ec']['y']), + ]; } - + /** - * Legacy mnemonic generation (deprecated) + * Compress an uncompressed public key point (x, y) into a 33-byte hex string. + * + * @param array{x: string, y: string} $point Elliptic curve point + * @return string Compressed public key (hex) */ - private function getLegacyMnemonic(): string + public static function compressPublicKey(array $point): string { - error_log("WARNING: Using legacy mnemonic generation - may contain duplicates!"); - - // Use BIP39 wordlist from Mnemonic class - $wordList = Mnemonic::getWordList(); - - if (empty($wordList)) { - throw new Exception("BIP39 word list not available"); - } - - $mnemonic = []; - $seed = $this->privateKey; - $usedIndices = []; - - for ($i = 0; $i < 12; $i++) { - $attempts = 0; - do { - $index = hexdec(substr($seed, ($i + $attempts) * 2 % 64, 2)) % count($wordList); - $attempts++; - - // Prevent infinite loop - if ($attempts > 100) { - error_log("WARNING: KeyPair::getLegacyMnemonic() - Could not generate unique words, allowing duplicates"); - break; - } - } while (in_array($index, $usedIndices) && $attempts <= 100); - - $usedIndices[] = $index; - $mnemonic[] = $wordList[$index]; - } - - $mnemonicString = implode(' ', $mnemonic); - - // Check for duplicates - if (count($mnemonic) !== count(array_unique($mnemonic))) { - error_log("WARNING: KeyPair::getLegacyMnemonic() generated mnemonic with duplicates: $mnemonicString"); - } - - return $mnemonicString; + $yLastByte = hexdec(substr($point['y'], -2)); + $prefix = ($yLastByte % 2 === 0) ? '02' : '03'; + return $prefix . $point['x']; } - + /** - * Sign message + * Build a PEM-encoded EC private key from hex. + * + * @param string $privateKeyHex Hex-encoded 32-byte private key + * @return string PEM-encoded EC private key */ - public function sign(string $message): string + private static function buildECPrivateKeyPEM(string $privateKeyHex): string { - return Signature::sign($message, $this->privateKey); + $der = self::buildECPrivateKeyDER($privateKeyHex); + $pem = "-----BEGIN EC PRIVATE KEY-----\n"; + $pem .= chunk_split(base64_encode($der), 64, "\n"); + $pem .= "-----END EC PRIVATE KEY-----\n"; + return $pem; } - + /** - * Verify signature + * Construct a raw ASN.1 DER-encoded EC private key using secp256k1 parameters. + * + * @param string $privateKeyHex 32-byte private key in hex + * @return string Binary DER-encoded EC private key */ - public function verify(string $message, string $signature): bool + private static function buildECPrivateKeyDER(string $privateKeyHex): string { - return Signature::verify($message, $signature, $this->publicKey); + $privateKeyBin = hex2bin($privateKeyHex); + $ecParams = hex2bin('a00706052b8104000a'); // secp256k1 OID + $version = hex2bin('020101'); // version = 1 + + $keyOctet = hex2bin('04') . chr(strlen($privateKeyBin)) . $privateKeyBin; + $keySeq = $version . chr(0x04) . chr(strlen($privateKeyBin)) . $privateKeyBin . $ecParams; + $seq = chr(0x30) . chr(strlen($keySeq)) . $keySeq; + + return $seq; } } diff --git a/core/Cryptography/Mnemonic.php b/core/Cryptography/Mnemonic.php index 9668d9a..1c0a9b9 100644 --- a/core/Cryptography/Mnemonic.php +++ b/core/Cryptography/Mnemonic.php @@ -10,213 +10,73 @@ */ class Mnemonic { - private static array $wordList = []; - /** - * Generate a new mnemonic phrase. - * - * @param int $strength The number of words (12, 15, 18, 21, 24) - * @return array The mnemonic phrase as an array of words. - * @throws Exception + * @var string[] Cached word list used for generating mnemonics */ - public static function generate(int $strength = 12): array - { - if (!in_array($strength, [12, 15, 18, 21, 24])) { - throw new Exception('Invalid strength, must be 12, 15, 18, 21, or 24.'); - } - - // Правильный расчет энтропии для BIP39 - $entropyLengthBits = match($strength) { - 12 => 128, - 15 => 160, - 18 => 192, - 21 => 224, - 24 => 256 - }; - - $entropyBytes = $entropyLengthBits / 8; - $entropy = random_bytes((int)$entropyBytes); - - error_log("Mnemonic::generate - Entropy bytes: " . $entropyBytes . ", hex: " . bin2hex($entropy)); - - $entropyBits = self::bytesToBits($entropy); - $checksumBits = self::deriveChecksumBits($entropy); - $bits = $entropyBits . $checksumBits; - - error_log("Mnemonic::generate - Total bits length: " . strlen($bits) . " (expected: " . ($strength * 11) . ")"); - - $chunks = str_split($bits, 11); - $words = []; - self::loadWordList(); - - $usedIndices = []; // Отслеживаем использованные индексы - $maxAttempts = 10; - $attempt = 0; - - do { - $attempt++; - if ($attempt > 1) { - // Генерируем новую энтропию при повторных попытках - $entropy = random_bytes((int)$entropyBytes); - $entropyBits = self::bytesToBits($entropy); - $checksumBits = self::deriveChecksumBits($entropy); - $bits = $entropyBits . $checksumBits; - $chunks = str_split($bits, 11); - error_log("Mnemonic::generate - Regenerating entropy, attempt $attempt"); - } - - $words = []; - $usedIndices = []; - $isValid = true; - - foreach ($chunks as $chunk) { - $index = bindec($chunk); - - // Проверяем, что индекс валидный и не повторяется - if ($index >= count(self::$wordList)) { - error_log("WARNING: Invalid word index: $index (max: " . (count(self::$wordList) - 1) . ")"); - $isValid = false; - break; - } - - if (in_array($index, $usedIndices)) { - error_log("WARNING: Duplicate word index $index detected, attempt $attempt"); - $isValid = false; - break; - } - - $usedIndices[] = $index; - $words[] = self::$wordList[$index]; - } - - // Дополнительная проверка на уникальность слов - if ($isValid && count($words) === count(array_unique($words))) { - error_log("Mnemonic::generate - Successfully generated " . count($words) . " unique words on attempt $attempt: " . implode(' ', $words)); - return $words; - } - - if ($isValid) { - error_log("WARNING: Duplicate words found in mnemonic, attempt $attempt"); - } - - } while ($attempt < $maxAttempts); - - throw new Exception('Failed to generate valid mnemonic after ' . $maxAttempts . ' attempts'); - - error_log("Mnemonic::generate - Generated " . count($words) . " unique words: " . implode(' ', $words)); - return $words; - } + protected static array $wordList = []; /** - * Converts a mnemonic phrase to a seed. + * Generate a 12-word BIP-39 compliant mnemonic phrase. * - * @param array $mnemonic The mnemonic phrase. - * @param string $passphrase Optional passphrase. - * @return string The resulting seed as a hex string. + * @return string Array of 12 words representing the mnemonic phrase + * @throws Exception If the word list file cannot be read */ - public static function toSeed(array $mnemonic, string $passphrase = ''): string - { - error_log("Mnemonic::toSeed - Starting with " . count($mnemonic) . " words"); - - $mnemonicString = implode(' ', $mnemonic); - error_log("Mnemonic::toSeed - Mnemonic string: " . $mnemonicString); - - $salt = 'mnemonic' . $passphrase; - $result = bin2hex(hash_pbkdf2('sha512', $mnemonicString, $salt, 2048, 64, true)); - - error_log("Mnemonic::toSeed - Generated seed length: " . strlen($result)); - return $result; - } + public static function generate(): string + { + if (empty(self::$wordList)) { + self::$wordList = explode( + "\n", + trim(file_get_contents(__DIR__ . '/../../storage/word_list.txt')) + ); + } + + $entropy = random_bytes(16); // 128 bits + $entropyBits = self::bytesToBits($entropy); + $checksumBits = substr(self::bytesToBits(hash('sha256', $entropy, TRUE)), 0, 4); + $bits = $entropyBits . $checksumBits; + + $chunks = str_split($bits, 11); + $mnemonic = []; + + foreach ($chunks as $chunk) { + $idx = bindec($chunk); + $mnemonic[] = preg_replace('/\s+/', ' ', trim(self::$wordList[$idx])); + } + + return implode(' ', $mnemonic); + } /** - * Validate a mnemonic phrase. + * Converts a mnemonic phrase and optional passphrase into a BIP-39 seed. * - * @param array $mnemonic The mnemonic phrase. - * @return bool True if valid, false otherwise. + * @param string $mnemonic The mnemonic phrase as a space-separated string + * @param string $passphrase Optional passphrase (empty by default) + * @return string 512-bit binary seed (64 bytes) + * @throws Exception If `ext-intl` is not installed (normalizer required) */ - public static function validate(array $mnemonic): bool - { - try { - self::loadWordList(); - $bits = ''; - foreach ($mnemonic as $word) { - $index = array_search($word, self::$wordList); - if ($index === false) { - return false; // Word not in list - } - $bits .= str_pad(decbin($index), 11, '0', STR_PAD_LEFT); - } - - $entropyBitsLength = (int)(floor(strlen($bits) / 33) * 32); - $checksumLength = strlen($bits) - $entropyBitsLength; - - if (!in_array($checksumLength, [4, 5, 6, 7, 8])) { - return false; - } - - $entropyBits = substr($bits, 0, $entropyBitsLength); - $checksumBits = substr($bits, $entropyBitsLength); + public static function toSeed(string $mnemonic, string $passphrase = ''): string +{ + if (!function_exists('normalizer_normalize')) { + throw new Exception("ext-intl is required for BIP-39 compliance (normalizer_normalize)"); + } - $entropyBytes = self::bitsToBytes($entropyBits); - $derivedChecksum = self::deriveChecksumBits($entropyBytes); + $mnemonicN = normalizer_normalize($mnemonic, Normalizer::FORM_KD); + $saltN = normalizer_normalize('mnemonic' . $passphrase, Normalizer::FORM_KD); - return $checksumBits === $derivedChecksum; - } catch (Exception $e) { - return false; - } - } + return hash_pbkdf2('sha512', $mnemonicN, $saltN, 2048, 64, true); +} /** - * Get word list (public access) - */ - public static function getWordList(): array - { - self::loadWordList(); - return self::$wordList; - } - - /** - * Load word list (public access) + * Converts a binary string into a string of bits. + * + * @param string $bytes Binary string (raw bytes) + * @return string Binary representation of the input (e.g., "11001010...") */ - public static function loadWordListPublic(): void - { - self::loadWordList(); - } - - private static function deriveChecksumBits(string $entropy): string - { - $entropyLength = strlen($entropy) * 8; - $checksumLength = $entropyLength / 32; - $hash = hash('sha256', $entropy, true); - $hashBits = self::bytesToBits($hash); - return substr($hashBits, 0, (int)$checksumLength); - } - private static function bytesToBits(string $bytes): string - { - $bits = ''; - for ($i = 0; $i < strlen($bytes); $i++) { - $bits .= str_pad(decbin(ord($bytes[$i])), 8, '0', STR_PAD_LEFT); - } - return $bits; - } - - private static function bitsToBytes(string $bits): string - { - $bytes = ''; - foreach (str_split($bits, 8) as $chunk) { - $bytes .= chr(bindec($chunk)); - } - return $bytes; - } - - private static function loadWordList(): void - { - if (empty(self::$wordList)) { - self::$wordList = [ - 'abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract', 'absurd', 'abuse', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid', 'acoustic', 'acquire', 'across', 'act', 'action', 'actor', 'actress', 'actual', 'adapt', 'add', 'addict', 'address', 'adjust', 'admit', 'adult', 'advance', 'advice', 'aerobic', 'affair', 'afford', 'afraid', 'again', 'age', 'agent', 'agree', 'ahead', 'aim', 'air', 'airport', 'aisle', 'alarm', 'album', 'alcohol', 'alert', 'alien', 'all', 'alley', 'allow', 'almost', 'alone', 'alpha', 'already', 'also', 'alter', 'always', 'amateur', 'amazing', 'among', 'amount', 'amused', 'analyst', 'anchor', 'ancient', 'anger', 'angle', 'angry', 'animal', 'ankle', 'announce', 'annual', 'another', 'answer', 'antenna', 'antique', 'anxiety', 'any', 'apart', 'apology', 'appear', 'apple', 'approve', 'april', 'arch', 'arctic', 'area', 'arena', 'argue', 'arm', 'armed', 'armor', 'army', 'around', 'arrange', 'arrest', 'arrive', 'arrow', 'art', 'artefact', 'artist', 'artwork', 'ask', 'aspect', 'assault', 'asset', 'assist', 'assume', 'asthma', 'athlete', 'atom', 'attack', 'attend', 'attitude', 'attract', 'auction', 'audit', 'august', 'aunt', 'author', 'auto', 'autumn', 'average', 'avocado', 'avoid', 'awake', 'aware', 'away', 'awesome', 'awful', 'awkward', 'axis', 'baby', 'bachelor', 'bacon', 'badge', 'bag', 'balance', 'balcony', 'ball', 'bamboo', 'banana', 'banner', 'bar', 'barely', 'bargain', 'barrel', 'base', 'basic', 'basket', 'battle', 'beach', 'bean', 'beauty', 'because', 'become', 'beef', 'before', 'begin', 'behave', 'behind', 'believe', 'below', 'belt', 'bench', 'benefit', 'best', 'betray', 'better', 'between', 'beyond', 'bicycle', 'bid', 'bike', 'bind', 'biology', 'bird', 'birth', 'bitter', 'black', 'blade', 'blame', 'blanket', 'blast', 'bleak', 'bless', 'blind', 'blood', 'blossom', 'blouse', 'blue', 'blur', 'blush', 'board', 'boat', 'body', 'boil', 'bomb', 'bone', 'bonus', 'book', 'boost', 'booth', 'border', 'boring', 'borrow', 'boss', 'bottom', 'bounce', 'box', 'boy', 'bracket', 'brain', 'brand', 'brass', 'brave', 'bread', 'breeze', 'brick', 'bridge', 'brief', 'bright', 'bring', 'brisk', 'broccoli', 'broken', 'bronze', 'broom', 'brother', 'brown', 'brush', 'bubble', 'buddy', 'budget', 'buffalo', 'build', 'bulb', 'bulk', 'bullet', 'bundle', 'bunker', 'burden', 'burger', 'burst', 'bus', 'business', 'busy', 'butter', 'buyer', 'buzz', 'cabbage', 'cabin', 'cable', 'cactus', 'cage', 'cake', 'call', 'calm', 'camera', 'camp', 'can', 'canal', 'cancel', 'candy', 'cannon', 'canoe', 'canvas', 'canyon', 'capable', 'capital', 'captain', 'car', 'carbon', 'card', 'cargo', 'carpet', 'carry', 'cart', 'case', 'cash', 'casino', 'castle', 'casual', 'cat', 'catalog', 'catch', 'category', 'cattle', 'caught', 'cause', 'caution', 'cave', 'ceiling', 'celery', 'cement', 'census', 'century', 'cereal', 'certain', 'chair', 'chalk', 'champion', 'change', 'chaos', 'chapter', 'charge', 'chase', 'chat', 'cheap', 'check', 'cheese', 'chef', 'cherry', 'chest', 'chicken', 'chief', 'child', 'chimney', 'choice', 'choose', 'chronic', 'chuckle', 'chunk', 'churn', 'cigar', 'cinnamon', 'circle', 'citizen', 'city', 'civil', 'claim', 'clap', 'clarify', 'claw', 'clay', 'clean', 'clerk', 'clever', 'click', 'client', 'cliff', 'climb', 'clinic', 'clip', 'clock', 'clog', 'close', 'cloth', 'cloud', 'clown', 'club', 'clump', 'cluster', 'clutch', 'coach', 'coast', 'coconut', 'code', 'coffee', 'coil', 'coin', 'collect', 'color', 'column', 'combine', 'come', 'comfort', 'comic', 'common', 'company', 'concert', 'conduct', 'confirm', 'congress', 'connect', 'consider', 'control', 'convince', 'cook', 'cool', 'copper', 'copy', 'coral', 'core', 'corn', 'correct', 'cost', 'cotton', 'couch', 'country', 'couple', 'course', 'cousin', 'cover', 'coyote', 'crack', 'cradle', 'craft', 'cram', 'crane', 'crash', 'crater', 'crawl', 'crazy', 'cream', 'credit', 'creek', 'crew', 'cricket', 'crime', 'crisp', 'critic', 'crop', 'cross', 'crouch', 'crowd', 'crucial', 'cruel', 'cruise', 'crumble', 'crunch', 'crush', 'cry', 'crystal', 'cube', 'culture', 'cup', 'cupboard', 'curious', 'current', 'curtain', 'curve', 'cushion', 'custom', 'cute', 'cycle', 'dad', 'damage', 'damp', 'dance', 'danger', 'daring', 'dash', 'daughter', 'dawn', 'day', 'deal', 'debate', 'debris', 'decade', 'december', 'decide', 'decline', 'decorate', 'decrease', 'deer', 'defense', 'define', 'defy', 'degree', 'delay', 'deliver', 'demand', 'demise', 'denial', 'dentist', 'deny', 'depart', 'depend', 'deposit', 'depth', 'deputy', 'derive', 'describe', 'desert', 'design', 'desk', 'despair', 'destroy', 'detail', 'detect', 'develop', 'device', 'devote', 'diagram', 'dial', 'diamond', 'diary', 'dice', 'diesel', 'diet', 'differ', 'digital', 'dignity', 'dilemma', 'dinner', 'dinosaur', 'direct', 'dirt', 'disagree', 'discover', 'disease', 'dish', 'dismiss', 'disorder', 'display', 'distance', 'divert', 'divide', 'divorce', 'dizzy', 'doctor', 'document', 'dog', 'doll', 'dolphin', 'domain', 'donate', 'donkey', 'donor', 'door', 'dose', 'double', 'dove', 'draft', 'dragon', 'drama', 'drastic', 'draw', 'dream', 'dress', 'drift', 'drill', 'drink', 'drip', 'drive', 'drop', 'drum', 'dry', 'duck', 'dumb', 'dune', 'during', 'dust', 'dutch', 'duty', 'dwarf', 'dynamic', 'eager', 'eagle', 'early', 'earn', 'earth', 'easily', 'east', 'easy', 'echo', 'ecology', 'economy', 'edge', 'edit', 'educate', 'effort', 'egg', 'eight', 'either', 'elbow', 'elder', 'electric', 'elegant', 'element', 'elephant', 'elevator', 'elite', 'else', 'embark', 'embody', 'embrace', 'emerge', 'emotion', 'employ', 'empower', 'empty', 'enable', 'enact', 'end', 'endless', 'endorse', 'enemy', 'energy', 'enforce', 'engage', 'engine', 'enhance', 'enjoy', 'enlist', 'enough', 'enrich', 'enroll', 'ensure', 'enter', 'entire', 'entry', 'envelope', 'episode', 'equal', 'equip', 'era', 'erase', 'erode', 'erosion', 'error', 'erupt', 'escape', 'essay', 'essence', 'estate', 'eternal', 'ethics', 'evidence', 'evil', 'evoke', 'evolve', 'exact', 'example', 'excess', 'exchange', 'excite', 'exclude', 'excuse', 'execute', 'exercise', 'exhaust', 'exhibit', 'exile', 'exist', 'exit', 'exotic', 'expand', 'expect', 'expire', 'explain', 'expose', 'express', 'extend', 'extra', 'eye', 'eyebrow', 'fabric', 'face', 'faculty', 'fade', 'faint', 'faith', 'fall', 'false', 'fame', 'family', 'famous', 'fan', 'fancy', 'fantasy', 'farm', 'fashion', 'fat', 'fatal', 'father', 'fatigue', 'fault', 'favorite', 'feature', 'february', 'federal', 'fee', 'feed', 'feel', 'female', 'fence', 'festival', 'fetch', 'fever', 'few', 'fiber', 'fiction', 'field', 'figure', 'file', 'film', 'filter', 'final', 'find', 'fine', 'finger', 'finish', 'fire', 'firm', 'first', 'fiscal', 'fish', 'fit', 'fitness', 'fix', 'flag', 'flame', 'flash', 'flat', 'flavor', 'flee', 'flight', 'flip', 'float', 'flock', 'floor', 'flower', 'fluid', 'flush', 'fly', 'foam', 'focus', 'fog', 'foil', 'fold', 'follow', 'food', 'foot', 'force', 'forest', 'forget', 'fork', 'fortune', 'forum', 'forward', 'fossil', 'foster', 'found', 'fox', 'fragile', 'frame', 'frequent', 'fresh', 'friend', 'fringe', 'frog', 'front', 'frost', 'frown', 'frozen', 'fruit', 'fuel', 'fun', 'funny', 'furnace', 'fury', 'future', 'gadget', 'gain', 'galaxy', 'gallery', 'game', 'gap', 'garage', 'garbage', 'garden', 'garlic', 'garment', 'gas', 'gasp', 'gate', 'gather', 'gauge', 'gaze', 'general', 'genius', 'genre', 'gentle', 'genuine', 'gesture', 'ghost', 'giant', 'gift', 'giggle', 'ginger', 'giraffe', 'girl', 'give', 'glad', 'glance', 'glare', 'glass', 'glide', 'glimpse', 'globe', 'gloom', 'glory', 'glove', 'glow', 'glue', 'goat', 'goddess', 'gold', 'good', 'goose', 'gorilla', 'gospel', 'gossip', 'govern', 'gown', 'grab', 'grace', 'grain', 'grant', 'grape', 'grass', 'gravity', 'great', 'green', 'grid', 'grief', 'grit', 'grocery', 'group', 'grow', 'grunt', 'guard', 'guess', 'guide', 'guilt', 'guitar', 'gun', 'gym', 'habit', 'hair', 'half', 'hammer', 'hamster', 'hand', 'happy', 'harbor', 'hard', 'harsh', 'harvest', 'hat', 'have', 'hawk', 'hazard', 'head', 'health', 'heart', 'heavy', 'hedgehog', 'height', 'hello', 'helmet', 'help', 'hen', 'hero', 'hidden', 'high', 'hill', 'hint', 'hip', 'hire', 'history', 'hobby', 'hockey', 'hold', 'hole', 'holiday', 'hollow', 'home', 'honey', 'hood', 'hope', 'horn', 'horror', 'horse', 'hospital', 'host', 'hotel', 'hour', 'hover', 'hub', 'huge', 'human', 'humble', 'humor', 'hundred', 'hungry', 'hunt', 'hurdle', 'hurry', 'hurt', 'husband', 'hybrid', 'ice', 'icon', 'idea', 'identify', 'idle', 'ignore', 'ill', 'illegal', 'illness', 'image', 'imitate', 'immense', 'immune', 'impact', 'impose', 'improve', 'impulse', 'inch', 'include', 'income', 'increase', 'index', 'indicate', 'indoor', 'industry', 'infant', 'inflict', 'inform', 'inhale', 'inherit', 'initial', 'inject', 'injury', 'inmate', 'inner', 'innocent', 'input', 'inquiry', 'insane', 'insect', 'inside', 'inspire', 'install', 'intact', 'interest', 'into', 'invest', 'invite', 'involve', 'iron', 'island', 'isolate', 'issue', 'item', 'ivory', 'jacket', 'jaguar', 'jar', 'jazz', 'jealous', 'jeans', 'jelly', 'jewel', 'job', 'join', 'joke', 'journey', 'joy', 'judge', 'juice', 'jump', 'jungle', 'junior', 'junk', 'just', 'kangaroo', 'keen', 'keep', 'ketchup', 'key', 'kick', 'kid', 'kidney', 'kind', 'kingdom', 'kiss', 'kit', 'kitchen', 'kite', 'kitten', 'kiwi', 'knee', 'knife', 'knock', 'know', 'lab', 'label', 'labor', 'ladder', 'lady', 'lake', 'lamp', 'language', 'laptop', 'large', 'later', 'latin', 'laugh', 'laundry', 'lava', 'law', 'lawn', 'lawsuit', 'layer', 'lazy', 'leader', 'leaf', 'learn', 'leave', 'lecture', 'left', 'leg', 'legal', 'legend', 'leisure', 'lemon', 'lend', 'length', 'lens', 'leopard', 'lesson', 'letter', 'level', 'liar', 'liberty', 'library', 'license', 'life', 'lift', 'light', 'like', 'limb', 'limit', 'link', 'lion', 'liquid', 'list', 'little', 'live', 'lizard', 'load', 'loan', 'lobster', 'local', 'lock', 'logic', 'lonely', 'long', 'loop', 'lottery', 'loud', 'lounge', 'love', 'loyal', 'lucky', 'luggage', 'lumber', 'lunar', 'lunch', 'luxury', 'lyrics', 'machine', 'mad', 'magic', 'magnet', 'maid', 'mail', 'main', 'major', 'make', 'mammal', 'man', 'manage', 'mandate', 'mango', 'mansion', 'manual', 'maple', 'marble', 'march', 'margin', 'marine', 'market', 'marriage', 'mask', 'mass', 'master', 'match', 'material', 'math', 'matrix', 'matter', 'maximum', 'maze', 'meadow', 'mean', 'measure', 'meat', 'mechanic', 'medal', 'media', 'melody', 'melt', 'member', 'memory', 'mention', 'menu', 'mercy', 'merge', 'merit', 'merry', 'mesh', 'message', 'metal', 'method', 'middle', 'midnight', 'milk', 'million', 'mimic', 'mind', 'minimum', 'minor', 'minute', 'miracle', 'mirror', 'misery', 'miss', 'mistake', 'mix', 'mixed', 'mixture', 'mobile', 'model', 'modify', 'mom', 'moment', 'monitor', 'monkey', 'monster', 'month', 'moon', 'moral', 'more', 'morning', 'mosquito', 'mother', 'motion', 'motor', 'mountain', 'mouse', 'move', 'movie', 'much', 'muffin', 'mule', 'multiply', 'muscle', 'museum', 'mushroom', 'music', 'must', 'mutual', 'myself', 'mystery', 'myth', 'naive', 'name', 'napkin', 'narrow', 'nasty', 'nation', 'nature', 'near', 'neck', 'need', 'negative', 'neglect', 'neither', 'nephew', 'nerve', 'nest', 'net', 'network', 'neutral', 'never', 'news', 'next', 'nice', 'night', 'noble', 'noise', 'nominee', 'noodle', 'normal', 'north', 'nose', 'notable', 'note', 'nothing', 'notice', 'novel', 'now', 'nuclear', 'number', 'nurse', 'nut', 'oak', 'obey', 'object', 'oblige', 'obscure', 'observe', 'obtain', 'obvious', 'occur', 'ocean', 'october', 'odor', 'off', 'offer', 'office', 'often', 'oil', 'okay', 'old', 'olive', 'olympic', 'omit', 'once', 'one', 'onion', 'online', 'only', 'open', 'opera', 'opinion', 'oppose', 'option', 'orange', 'orbit', 'orchard', 'order', 'ordinary', 'organ', 'orient', 'original', 'orphan', 'ostrich', 'other', 'outdoor', 'outer', 'output', 'outside', 'oval', 'oven', 'over', 'own', 'owner', 'oxygen', 'oyster', 'ozone', 'pact', 'paddle', 'page', 'pair', 'palace', 'palm', 'panda', 'panel', 'panic', 'panther', 'paper', 'parade', 'parent', 'park', 'parrot', 'party', 'pass', 'patch', 'path', 'patient', 'patrol', 'pattern', 'pause', 'pave', 'payment', 'peace', 'peanut', 'pear', 'peasant', 'pelican', 'pen', 'penalty', 'pencil', 'people', 'pepper', 'perfect', 'permit', 'person', 'pet', 'phone', 'photo', 'phrase', 'physical', 'piano', 'picnic', 'picture', 'piece', 'pig', 'pigeon', 'pill', 'pilot', 'pink', 'pioneer', 'pipe', 'pistol', 'pitch', 'pizza', 'place', 'planet', 'plastic', 'plate', 'play', 'please', 'pledge', 'pluck', 'plug', 'plunge', 'poem', 'poet', 'point', 'polar', 'pole', 'police', 'pond', 'pony', 'pool', 'popular', 'portion', 'position', 'possible', 'post', 'potato', 'pottery', 'poverty', 'powder', 'power', 'practice', 'praise', 'predict', 'prefer', 'prepare', 'present', 'pretty', 'prevent', 'price', 'pride', 'primary', 'print', 'priority', 'prison', 'private', 'prize', 'problem', 'process', 'produce', 'profit', 'program', 'project', 'promote', 'proof', 'property', 'prosper', 'protect', 'proud', 'provide', 'public', 'pudding', 'pull', 'pulp', 'pulse', 'pumpkin', 'punch', 'pupil', 'puppy', 'purchase', 'purity', 'purpose', 'push', 'put', 'puzzle', 'pyramid', 'quality', 'quantum', 'quarter', 'question', 'quick', 'quit', 'quiz', 'quote', 'rabbit', 'raccoon', 'race', 'rack', 'radar', 'radio', 'rail', 'rain', 'raise', 'rally', 'ramp', 'ranch', 'random', 'range', 'rapid', 'rare', 'rate', 'rather', 'raven', 'raw', 'razor', 'ready', 'real', 'reason', 'rebel', 'rebuild', 'recall', 'receive', 'recipe', 'record', 'recycle', 'reduce', 'reflect', 'reform', 'refuse', 'region', 'regret', 'regular', 'reject', 'relax', 'release', 'relief', 'rely', 'remain', 'remember', 'remind', 'remove', 'render', 'renew', 'rent', 'reopen', 'repair', 'repeat', 'replace', 'report', 'require', 'rescue', 'resemble', 'resist', 'resource', 'response', 'result', 'retire', 'retreat', 'return', 'reunion', 'reveal', 'review', 'reward', 'rhythm', 'rib', 'ribbon', 'rice', 'rich', 'ride', 'ridge', 'rifle', 'right', 'rigid', 'ring', 'riot', 'rip', 'ripe', 'rise', 'risk', 'ritua', 'rival', 'river', 'road', 'roast', 'robot', 'robust', 'rocket', 'romance', 'roof', 'rookie', 'room', 'rose', 'rotate', 'rough', 'round', 'route', 'royal', 'rubber', 'rude', 'rug', 'rule', 'run', 'runway', 'rural', 'sad', 'saddle', 'sadness', 'safe', 'sail', 'salad', 'salmon', 'salon', 'salt', 'salute', 'same', 'sample', 'sand', 'satisfy', 'satoshi', 'sauce', 'sausage', 'save', 'say', 'scale', 'scan', 'scare', 'scatter', 'scene', 'scheme', 'school', 'science', 'scissors', 'scorpion', 'scout', 'scrap', 'screen', 'script', 'scrub', 'sea', 'search', 'season', 'seat', 'second', 'secret', 'section', 'security', 'seed', 'seek', 'segment', 'select', 'sell', 'seminar', 'senior', 'sense', 'sentence', 'series', 'service', 'session', 'settle', 'setup', 'seven', 'shadow', 'shaft', 'shallow', 'share', 'shed', 'shell', 'sheriff', 'shield', 'shift', 'shine', 'ship', 'shiver', 'shock', 'shoe', 'shoot', 'shop', 'short', 'shoulder', 'shove', 'shrimp', 'shrug', 'shuffle', 'shy', 'sibling', 'sick', 'side', 'siege', 'sight', 'sign', 'silent', 'silk', 'silly', 'silver', 'similar', 'simple', 'since', 'sing', 'siren', 'sister', 'situate', 'six', 'size', 'skate', 'sketch', 'ski', 'skill', 'skin', 'skirt', 'skull', 'slab', 'slam', 'sleep', 'slender', 'slice', 'slide', 'slight', 'slim', 'slogan', 'slot', 'slow', 'slush', 'small', 'smart', 'smile', 'smoke', 'smooth', 'snack', 'snake', 'snap', 'sniff', 'snow', 'soap', 'soccer', 'social', 'sock', 'soda', 'soft', 'solar', 'soldier', 'solid', 'solution', 'solve', 'someone', 'song', 'soon', 'sorry', 'sort', 'soul', 'sound', 'soup', 'source', 'south', 'space', 'spare', 'spark', 'speak', 'special', 'speed', 'spell', 'spend', 'sphere', 'spice', 'spider', 'spike', 'spin', 'spirit', 'split', 'spoil', 'sponsor', 'spoon', 'sport', 'spot', 'spray', 'spread', 'spring', 'spy', 'square', 'squeeze', 'squirrel', 'stable', 'stadium', 'staff', 'stage', 'stairs', 'stamp', 'stand', 'start', 'state', 'stay', 'steak', 'steel', 'stem', 'step', 'stereo', 'stick', 'still', 'sting', 'stock', 'stomach', 'stone', 'stool', 'story', 'stove', 'strategy', 'street', 'strike', 'strong', 'struggle', 'student', 'stuff', 'stumble', 'style', 'subject', 'submit', 'subway', 'success', 'such', 'sudden', 'suffer', 'sugar', 'suggest', 'suit', 'summer', 'sun', 'sunny', 'sunset', 'super', 'supply', 'support', 'sure', 'surface', 'surge', 'surprise', 'surround', 'survey', 'suspect', 'sustain', 'swallow', 'swamp', 'swap', 'swarm', 'swear', 'sweet', 'swift', 'swim', 'swing', 'switch', 'sword', 'symbol', 'symptom', 'syrup', 'system', 'table', 'tackle', 'tag', 'tail', 'talent', 'talk', 'tank', 'tape', 'target', 'task', 'taste', 'tattoo', 'taxi', 'teach', 'team', 'tell', 'ten', 'tenant', 'tennis', 'tent', 'term', 'test', 'text', 'thank', 'that', 'theme', 'then', 'theory', 'there', 'they', 'thing', 'this', 'thought', 'three', 'thrive', 'throw', 'thumb', 'thunder', 'ticket', 'tide', 'tiger', 'tilt', 'timber', 'time', 'tiny', 'tip', 'tired', 'tissue', 'title', 'toast', 'tobacco', 'today', 'toe', 'together', 'toilet', 'token', 'tomato', 'tomorrow', 'tone', 'tongue', 'tonight', 'tool', 'tooth', 'top', 'topic', 'topple', 'torch', 'tornado', 'tortoise', 'toss', 'total', 'tourist', 'toward', 'tower', 'town', 'toy', 'track', 'trade', 'traffic', 'tragic', 'train', 'transfer', 'trap', 'trash', 'travel', 'tray', 'treat', 'tree', 'trend', 'trial', 'tribe', 'trick', 'trigger', 'trim', 'trip', 'trophy', 'trouble', 'truck', 'true', 'truly', 'trumpet', 'trust', 'truth', 'try', 'tube', 'tuition', 'tumble', 'tuna', 'tunnel', 'turkey', 'turn', 'turtle', 'twelve', 'twenty', 'twice', 'twin', 'twist', 'two', 'type', 'typical', 'ugly', 'umbrella', 'unable', 'unaware', 'uncle', 'uncover', 'under', 'undo', 'unfair', 'unfold', 'unhappy', 'uniform', 'unique', 'unit', 'universe', 'unknown', 'unlock', 'until', 'unusual', 'unveil', 'update', 'upgrade', 'uphold', 'upon', 'upper', 'upset', 'urban', 'urge', 'usage', 'use', 'used', 'useful', 'useless', 'usual', 'utility', 'vacant', 'vacuum', 'vague', 'valid', 'valley', 'valve', 'van', 'vanish', 'vapor', 'various', 'vast', 'vault', 'vehicle', 'velvet', 'vendor', 'venture', 'venue', 'verb', 'verify', 'version', 'very', 'vessel', 'veteran', 'viable', 'vibrant', 'vicious', 'victory', 'video', 'view', 'village', 'vintage', 'violin', 'virtual', 'virus', 'visa', 'visit', 'visual', 'vital', 'vivid', 'vocal', 'voice', 'void', 'volcano', 'volume', 'vote', 'voyage', 'wage', 'wagon', 'wait', 'walk', 'wall', 'walnut', 'want', 'warfare', 'warm', 'warrior', 'wash', 'wasp', 'waste', 'water', 'wave', 'way', 'wealth', 'weapon', 'wear', 'weasel', 'weather', 'web', 'wedding', 'weekend', 'weird', 'welcome', 'west', 'wet', 'whale', 'what', 'wheat', 'wheel', 'when', 'where', 'whip', 'whisper', 'wide', 'width', 'wife', 'wild', 'will', 'win', 'window', 'wine', 'wing', 'wink', 'winner', 'winter', 'wire', 'wisdom', 'wise', 'wish', 'witness', 'wolf', 'woman', 'wonder', 'wood', 'wool', 'word', 'work', 'world', 'worry', 'worth', 'wrap', 'wreck', 'wrestle', 'wrist', 'write', 'wrong', 'yard', 'year', 'yellow', 'you', 'young', 'youth', 'zebra', 'zero', 'zone', 'zoo' - ]; - } - } +{ + return implode('', array_map( + fn($c) => str_pad(decbin(ord($c)), 8, '0', STR_PAD_LEFT), + str_split($bytes) + )); } -?> +} \ No newline at end of file diff --git a/storage/word_list.txt b/storage/word_list.txt new file mode 100644 index 0000000..f78ccaf --- /dev/null +++ b/storage/word_list.txt @@ -0,0 +1,2048 @@ +abandon +ability +able +about +above +absent +absorb +abstract +absurd +abuse +access +accident +account +accuse +achieve +acid +acoustic +acquire +across +act +action +actor +actress +actual +adapt +add +addict +address +adjust +admit +adult +advance +advice +aerobic +affair +afford +afraid +again +age +agent +agree +ahead +aim +air +airport +aisle +alarm +album +alcohol +alert +alien +all +alley +allow +almost +alone +alpha +already +also +alter +always +amateur +amazing +among +amount +amused +analyst +anchor +ancient +anger +angle +angry +animal +ankle +announce +annual +another +answer +antenna +antique +anxiety +any +apart +apology +appear +apple +approve +april +arch +arctic +area +arena +argue +arm +armed +armor +army +around +arrange +arrest +arrive +arrow +art +artefact +artist +artwork +ask +aspect +assault +asset +assist +assume +asthma +athlete +atom +attack +attend +attitude +attract +auction +audit +august +aunt +author +auto +autumn +average +avocado +avoid +awake +aware +away +awesome +awful +awkward +axis +baby +bachelor +bacon +badge +bag +balance +balcony +ball +bamboo +banana +banner +bar +barely +bargain +barrel +base +basic +basket +battle +beach +bean +beauty +because +become +beef +before +begin +behave +behind +believe +below +belt +bench +benefit +best +betray +better +between +beyond +bicycle +bid +bike +bind +biology +bird +birth +bitter +black +blade +blame +blanket +blast +bleak +bless +blind +blood +blossom +blouse +blue +blur +blush +board +boat +body +boil +bomb +bone +bonus +book +boost +border +boring +borrow +boss +bottom +bounce +box +boy +bracket +brain +brand +brass +brave +bread +breeze +brick +bridge +brief +bright +bring +brisk +broccoli +broken +bronze +broom +brother +brown +brush +bubble +buddy +budget +buffalo +build +bulb +bulk +bullet +bundle +bunker +burden +burger +burst +bus +business +busy +butter +buyer +buzz +cabbage +cabin +cable +cactus +cage +cake +call +calm +camera +camp +can +canal +cancel +candy +cannon +canoe +canvas +canyon +capable +capital +captain +car +carbon +card +cargo +carpet +carry +cart +case +cash +casino +castle +casual +cat +catalog +catch +category +cattle +caught +cause +caution +cave +ceiling +celery +cement +census +century +cereal +certain +chair +chalk +champion +change +chaos +chapter +charge +chase +chat +cheap +check +cheese +chef +cherry +chest +chicken +chief +child +chimney +choice +choose +chronic +chuckle +chunk +churn +cigar +cinnamon +circle +citizen +city +civil +claim +clap +clarify +claw +clay +clean +clerk +clever +click +client +cliff +climb +clinic +clip +clock +clog +close +cloth +cloud +clown +club +clump +cluster +clutch +coach +coast +coconut +code +coffee +coil +coin +collect +color +column +combine +come +comfort +comic +common +company +concert +conduct +confirm +congress +connect +consider +control +convince +cook +cool +copper +copy +coral +core +corn +correct +cost +cotton +couch +country +couple +course +cousin +cover +coyote +crack +cradle +craft +cram +crane +crash +crater +crawl +crazy +cream +credit +creek +crew +cricket +crime +crisp +critic +crop +cross +crouch +crowd +crucial +cruel +cruise +crumble +crunch +crush +cry +crystal +cube +culture +cup +cupboard +curious +current +curtain +curve +cushion +custom +cute +cycle +dad +damage +damp +dance +danger +daring +dash +daughter +dawn +day +deal +debate +debris +decade +december +decide +decline +decorate +decrease +deer +defense +define +defy +degree +delay +deliver +demand +demise +denial +dentist +deny +depart +depend +deposit +depth +deputy +derive +describe +desert +design +desk +despair +destroy +detail +detect +develop +device +devote +diagram +dial +diamond +diary +dice +diesel +diet +differ +digital +dignity +dilemma +dinner +dinosaur +direct +dirt +disagree +discover +disease +dish +dismiss +disorder +display +distance +divert +divide +divorce +dizzy +doctor +document +dog +doll +dolphin +domain +donate +donkey +donor +door +dose +double +dove +draft +dragon +drama +drastic +draw +dream +dress +drift +drill +drink +drip +drive +drop +drum +dry +duck +dumb +dune +during +dust +dutch +duty +dwarf +dynamic +eager +eagle +early +earn +earth +easily +east +easy +echo +ecology +economy +edge +edit +educate +effort +egg +eight +either +elbow +elder +electric +elegant +element +elephant +elevator +elite +else +embark +embody +embrace +emerge +emotion +employ +empower +empty +enable +enact +end +endless +endorse +enemy +energy +enforce +engage +engine +enhance +enjoy +enlist +enough +enrich +enroll +ensure +enter +entire +entry +envelope +episode +equal +equip +era +erase +erode +erosion +error +erupt +escape +essay +essence +estate +eternal +ethics +evidence +evil +evoke +evolve +exact +example +excess +exchange +excite +exclude +excuse +execute +exercise +exhaust +exhibit +exile +exist +exit +exotic +expand +expect +expire +explain +expose +express +extend +extra +eye +eyebrow +fabric +face +faculty +fade +faint +faith +fall +false +fame +family +famous +fan +fancy +fantasy +farm +fashion +fat +fatal +father +fatigue +fault +favorite +feature +february +federal +fee +feed +feel +female +fence +festival +fetch +fever +few +fiber +fiction +field +figure +file +film +filter +final +find +fine +finger +finish +fire +firm +first +fiscal +fish +fit +fitness +fix +flag +flame +flash +flat +flavor +flee +flight +flip +float +flock +floor +flower +fluid +flush +fly +foam +focus +fog +foil +fold +follow +food +foot +force +forest +forget +fork +fortune +forum +forward +fossil +foster +found +fox +fragile +frame +frequent +fresh +friend +fringe +frog +front +frost +frown +frozen +fruit +fuel +fun +funny +furnace +fury +future +gadget +gain +galaxy +gallery +game +gap +garage +garbage +garden +garlic +garment +gas +gasp +gate +gather +gauge +gaze +general +genius +genre +gentle +genuine +gesture +ghost +giant +gift +giggle +ginger +giraffe +girl +give +glad +glance +glare +glass +glide +glimpse +globe +gloom +glory +glove +glow +glue +goat +goddess +gold +good +goose +gorilla +gospel +gossip +govern +gown +grab +grace +grain +grant +grape +grass +gravity +great +green +grid +grief +grit +grocery +group +grow +grunt +guard +guess +guide +guilt +guitar +gun +gym +habit +hair +half +hammer +hamster +hand +happy +harbor +hard +harsh +harvest +hat +have +hawk +hazard +head +health +heart +heavy +hedgehog +height +hello +helmet +help +hen +hero +hidden +high +hill +hint +hip +hire +history +hobby +hockey +hold +hole +holiday +hollow +home +honey +hood +hope +horn +horror +horse +hospital +host +hotel +hour +hover +hub +huge +human +humble +humor +hundred +hungry +hunt +hurdle +hurry +hurt +husband +hybrid +ice +icon +idea +identify +idle +ignore +ill +illegal +illness +image +imitate +immense +immune +impact +impose +improve +impulse +inch +include +income +increase +index +indicate +indoor +industry +infant +inflict +inform +inhale +inherit +initial +inject +injury +inmate +inner +innocent +input +inquiry +insane +insect +inside +inspire +install +intact +interest +into +invest +invite +involve +iron +island +isolate +issue +item +ivory +jacket +jaguar +jar +jazz +jealous +jeans +jelly +jewel +job +join +joke +journey +joy +judge +juice +jump +jungle +junior +junk +just +kangaroo +keen +keep +ketchup +key +kick +kid +kidney +kind +kingdom +kiss +kit +kitchen +kite +kitten +kiwi +knee +knife +knock +know +lab +label +labor +ladder +lady +lake +lamp +language +laptop +large +later +latin +laugh +laundry +lava +law +lawn +lawsuit +layer +lazy +leader +leaf +learn +leave +lecture +left +leg +legal +legend +leisure +lemon +lend +length +lens +leopard +lesson +letter +level +liar +liberty +library +license +life +lift +light +like +limb +limit +link +lion +liquid +list +little +live +lizard +load +loan +lobster +local +lock +logic +lonely +long +loop +lottery +loud +lounge +love +loyal +lucky +luggage +lumber +lunar +lunch +luxury +lyrics +machine +mad +magic +magnet +maid +mail +main +major +make +mammal +man +manage +mandate +mango +mansion +manual +maple +marble +march +margin +marine +market +marriage +mask +mass +master +match +material +math +matrix +matter +maximum +maze +meadow +mean +measure +meat +mechanic +medal +media +melody +melt +member +memory +mention +menu +mercy +merge +merit +merry +mesh +message +metal +method +middle +midnight +milk +million +mimic +mind +minimum +minor +minute +miracle +mirror +misery +miss +mistake +mix +mixed +mixture +mobile +model +modify +mom +moment +monitor +monkey +monster +month +moon +moral +more +morning +mosquito +mother +motion +motor +mountain +mouse +move +movie +much +muffin +mule +multiply +muscle +museum +mushroom +music +must +mutual +myself +mystery +myth +naive +name +napkin +narrow +nasty +nation +nature +near +neck +need +negative +neglect +neither +nephew +nerve +nest +net +network +neutral +never +news +next +nice +night +noble +noise +nominee +noodle +normal +north +nose +notable +note +nothing +notice +novel +now +nuclear +number +nurse +nut +oak +obey +object +oblige +obscure +observe +obtain +obvious +occur +ocean +october +odor +off +offer +office +often +oil +okay +old +olive +olympic +omit +once +one +onion +online +only +open +opera +opinion +oppose +option +orange +orbit +orchard +order +ordinary +organ +orient +original +orphan +ostrich +other +outdoor +outer +output +outside +oval +oven +over +own +owner +oxygen +oyster +ozone +pact +paddle +page +pair +palace +palm +panda +panel +panic +panther +paper +parade +parent +park +parrot +party +pass +patch +path +patient +patrol +pattern +pause +pave +payment +peace +peanut +pear +peasant +pelican +pen +penalty +pencil +people +pepper +perfect +permit +person +pet +phone +photo +phrase +physical +piano +picnic +picture +piece +pig +pigeon +pill +pilot +pink +pioneer +pipe +pistol +pitch +pizza +place +planet +plastic +plate +play +please +pledge +pluck +plug +plunge +poem +poet +point +polar +pole +police +pond +pony +pool +popular +portion +position +possible +post +potato +pottery +poverty +powder +power +practice +praise +predict +prefer +prepare +present +pretty +prevent +price +pride +primary +print +priority +prison +private +prize +problem +process +produce +profit +program +project +promote +proof +property +prosper +protect +proud +provide +public +pudding +pull +pulp +pulse +pumpkin +punch +pupil +puppy +purchase +purity +purpose +purse +push +put +puzzle +pyramid +quality +quantum +quarter +question +quick +quit +quiz +quote +rabbit +raccoon +race +rack +radar +radio +rail +rain +raise +rally +ramp +ranch +random +range +rapid +rare +rate +rather +raven +raw +razor +ready +real +reason +rebel +rebuild +recall +receive +recipe +record +recycle +reduce +reflect +reform +refuse +region +regret +regular +reject +relax +release +relief +rely +remain +remember +remind +remove +render +renew +rent +reopen +repair +repeat +replace +report +require +rescue +resemble +resist +resource +response +result +retire +retreat +return +reunion +reveal +review +reward +rhythm +rib +ribbon +rice +rich +ride +ridge +rifle +right +rigid +ring +riot +ripple +risk +ritual +rival +river +road +roast +robot +robust +rocket +romance +roof +rookie +room +rose +rotate +rough +round +route +royal +rubber +rude +rug +rule +run +runway +rural +sad +saddle +sadness +safe +sail +salad +salmon +salon +salt +salute +same +sample +sand +satisfy +satoshi +sauce +sausage +save +say +scale +scan +scare +scatter +scene +scheme +school +science +scissors +scorpion +scout +scrap +screen +script +scrub +sea +search +season +seat +second +secret +section +security +seed +seek +segment +select +sell +seminar +senior +sense +sentence +series +service +session +settle +setup +seven +shadow +shaft +shallow +share +shed +shell +sheriff +shield +shift +shine +ship +shiver +shock +shoe +shoot +shop +short +shoulder +shove +shrimp +shrug +shuffle +shy +sibling +sick +side +siege +sight +sign +silent +silk +silly +silver +similar +simple +since +sing +siren +sister +situate +six +size +skate +sketch +ski +skill +skin +skirt +skull +slab +slam +sleep +slender +slice +slide +slight +slim +slogan +slot +slow +slush +small +smart +smile +smoke +smooth +snack +snake +snap +sniff +snow +soap +soccer +social +sock +soda +soft +solar +soldier +solid +solution +solve +someone +song +soon +sorry +sort +soul +sound +soup +source +south +space +spare +spatial +spawn +speak +special +speed +spell +spend +sphere +spice +spider +spike +spin +spirit +split +spoil +sponsor +spoon +sport +spot +spray +spread +spring +spy +square +squeeze +squirrel +stable +stadium +staff +stage +stairs +stamp +stand +start +state +stay +steak +steel +stem +step +stereo +stick +still +sting +stock +stomach +stone +stool +story +stove +strategy +street +strike +strong +struggle +student +stuff +stumble +style +subject +submit +subway +success +such +sudden +suffer +sugar +suggest +suit +summer +sun +sunny +sunset +super +supply +supreme +sure +surface +surge +surprise +surround +survey +suspect +sustain +swallow +swamp +swap +swarm +swear +sweet +swift +swim +swing +switch +sword +symbol +symptom +syrup +system +table +tackle +tag +tail +talent +talk +tank +tape +target +task +taste +tattoo +taxi +teach +team +tell +ten +tenant +tennis +tent +term +test +text +thank +that +theme +then +theory +there +they +thing +this +thought +three +thrive +throw +thumb +thunder +ticket +tide +tiger +tilt +timber +time +tiny +tip +tired +tissue +title +toast +tobacco +today +toddler +toe +together +toilet +token +tomato +tomorrow +tone +tongue +tonight +tool +tooth +top +topic +topple +torch +tornado +tortoise +toss +total +tourist +toward +tower +town +toy +track +trade +traffic +tragic +train +transfer +trap +trash +travel +tray +treat +tree +trend +trial +tribe +trick +trigger +trim +trip +trophy +trouble +truck +true +truly +trumpet +trust +truth +try +tube +tuition +tumble +tuna +tunnel +turkey +turn +turtle +twelve +twenty +twice +twin +twist +two +type +typical +ugly +umbrella +unable +unaware +uncle +uncover +under +undo +unfair +unfold +unhappy +uniform +unique +unit +universe +unknown +unlock +until +unusual +unveil +update +upgrade +uphold +upon +upper +upset +urban +urge +usage +use +used +useful +useless +usual +utility +vacant +vacuum +vague +valid +valley +valve +van +vanish +vapor +various +vast +vault +vehicle +velvet +vendor +venture +venue +verb +verify +version +very +vessel +veteran +viable +vibrant +vicious +victory +video +view +village +vintage +violin +virtual +virus +visa +visit +visual +vital +vivid +vocal +voice +void +volcano +volume +vote +voyage +wage +wagon +wait +walk +wall +walnut +want +warfare +warm +warrior +wash +wasp +waste +water +wave +way +wealth +weapon +wear +weasel +weather +web +wedding +weekend +weird +welcome +west +wet +whale +what +wheat +wheel +when +where +whip +whisper +wide +width +wife +wild +will +win +window +wine +wing +wink +winner +winter +wire +wisdom +wise +wish +witness +wolf +woman +wonder +wood +wool +word +work +world +worry +worth +wrap +wreck +wrestle +wrist +write +wrong +yard +year +yellow +you +young +youth +zebra +zero +zone +zoo \ No newline at end of file diff --git a/wallet/HDWallet.php b/wallet/HDWallet.php new file mode 100644 index 0000000..63d3c92 --- /dev/null +++ b/wallet/HDWallet.php @@ -0,0 +1,97 @@ +getAddress(); // Store wallet in database only if requested @@ -104,7 +104,7 @@ public function generateMnemonic(): array /** * Create a new wallet from a mnemonic phrase */ - public function createWalletFromMnemonic(array $mnemonic): array + public function createWalletFromMnemonic(string $mnemonic): array { try { $keyPair = KeyPair::fromMnemonic($mnemonic); @@ -141,7 +141,7 @@ public function createWalletFromMnemonic(array $mnemonic): array /** * Restore wallet from mnemonic phrase */ - public function restoreWalletFromMnemonic(array $mnemonic): array + public function restoreWalletFromMnemonic(string $mnemonic): array { try { // Debug: проверим что получили