Search code examples
phpcryptographytron

how to generate Trx wallet without using API


base on TRX documents and some search in GitHub I tried to generate wallet offline and I can't use API for some reasons.

based on Trx documents I should do these steps :

  1. Generate a key pair and extract the public key (a 64-byte byte array representing its x,y coordinates).
  2. Hash the public key using sha3-256 function and extract the last 20 bytes of the result.
  3. Add 0x41 to the beginning of the byte array. The length of the initial address should be 21 bytes.
  4. Hash the address twice using sha256 function and take the first 4 bytes as verification code.
  5. Add the verification code to the end of the initial address and get an address in base58check format through base58 encoding.
  6. An encoded Mainnet address begins with T and is 34 bytes in length.

Please note: the sha3 protocol adopted is KECCAK-256.

I find mattvb91/tron-trx-php in GitHub and this repository there is a wallet generator method /src/Wallet.php but the generated key validation return an Error Exception and validation get failed.

I try to recode mattvb91/tron-trx-php Wallet generator method and create my wallet generator

class walletGenerator
    {

        private $addressPrefix = "41";
        private $addressPrefixByte = 0x41;
        private $addressSize = 34;

        public function __construct()
        {

        }

        public function generateWallet()
        {
            $key = new Key();

            $odd = false;
            while (!$odd)
            {
                $keyPair = $key->GenerateKeypair();
                if(strlen($keyPair['public_key']) % 2 == 0) $odd = true;
            }

            $privateKeyHex = $keyPair['private_key_hex'];
            $pubKeyHex = $keyPair['public_key'];

            $pubKeyBin = hex2bin($pubKeyHex);
            $addressHex = $this->getAddressHex($pubKeyBin);
            $addressBin = hex2bin($addressHex);
            $addressBase58 = $this->getBase58CheckAddress($addressBin);
            $validAddress = $this->validateAddress($addressBase58);

        }

        private function getAddressHex($pubKeyBin)
        {
            if (strlen($pubKeyBin) == 65) {
                $pubKeyBin = substr($pubKeyBin, 1);
            }

            $hash = Keccak::hash($pubKeyBin , 256);
            $hash = substr($hash, 24);

            return $this->addressPrefix . $hash;
        }

        private function getBase58CheckAddress($addressBin){
            $hash0 = Hash::SHA256($addressBin);
            $hash1 = Hash::SHA256($hash0);
            $checksum = substr($hash1, 0, 4);
            $checksum = $addressBin . $checksum;
            $result = Base58::encode(Crypto::bin2bc($checksum));

            return $result;
        }

        private function validateAddress($walletAddress){
            if(strlen($walletAddress) !== $this->addressSize) return false;

            $address = Base58Check::decode($walletAddress , false , 0 , false);
            $utf8 = hex2bin($address);

            if(strlen($utf8) !== 25) return false;
            if(strpos($utf8 , $this->addressPrefixByte) !== 0) return false; // strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior

            $checkSum = substr($utf8, 21);
            $address = substr($utf8, 0, 21);


            $hash0 = Hash::SHA256($address);
            $hash1 = Hash::SHA256($hash0);
            $checkSum1 = substr($hash1, 0, 4);

            if ($checkSum === $checkSum1) {
                return true;
            }
        }

Here is my problems :

  1. validateAddress method has an Error Exception
  2. when I add Private Key in Trx Wallets manually the detected wallet address is different from the generated Address.
if(strpos($utf8 , $this->addressPrefixByte) !== 0) return false; // strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior

additional information

I used ionux/phactor to generating keyPair and iexbase/tron-api Support classes for Hash and ...


Solution

  • I can debug and solved the problem and share the solutions with you

    nowhere is the solutions

    this line of code has an Error Exception

    if(strpos($utf8 , $this->addressPrefixByte) !== 0) return false; // strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior
    

    this problem because of PHP 7.3 bugs and fix with PHP 7.2 ( Exception: stripos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior #770 )

    and addresses differences

    in the Key Pair array, I remove 0x from first of Private Key Hex and I can access to the wallet in Tron Link Extention don't remember to have a transition for wallet activation