Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Is possible to generate new account offline #35

Open
amandiobm opened this issue Sep 4, 2018 · 8 comments
Open

[Question] Is possible to generate new account offline #35

amandiobm opened this issue Sep 4, 2018 · 8 comments

Comments

@amandiobm
Copy link

Hi guys, how's going?

I very new on the blockchain, ethereum, all that stuff, and I have some sort of an "issue".

I saw a lot of libraries to work with ethereum in PHP and basically, all of them needs a connection with some ethereum network to work. But I noticed a lot of that networks as a service they don't allow us to create address/wallet/account due to security issues.

So there any way that I can generate those address offline? I saw this post and it seems possible to create offline.

I was thinking to add that feature. As an optional param to generate offline. We still will be needing a network to connect into, but that address part will be optional, with the default value as 'false'. If the network allows you to create, that one already works. If not allows, just change to 'true'.

What do you guys think?

Sorry if I said something wrong. Still learning.

Kind regards.

Amandio.

@digitaldonkey
Copy link
Owner

Technically Ethereum addresses are independent from any network. They just derived from a "private key" which is just some random string. Visible on chain are only the transactions from/to an account address.

You may use a wallet like Metamask to create them. I don't know of any PHP wallet currently, but it would be great to add this function in this library (And by experience, I'm sure soon after you'll find some content here too ;) )

Summing up as opposed to contract addresses (which are deployed on chain) account addresses are technically network independent, so you don't need a network to connect to.

The param stuff I actually don't understand, I guess it's not necessary. I'm to answer more questions on that.

@amandiobm
Copy link
Author

Hey @digitaldonkey, I managed to create address "offline". The code is based on that post that I sent to you, and also based on the implementation of ethereum/web3.js.

I used two dependencies to reach my goal. kornrunner/php-keccak, and mdanter/ecc.

/**
 * @param null $entropy
 * @return array
 * @throws \Exception
 */
public function generateAddress($entropy = '')
{
    $generator = EccFactory::getNistCurves()->generator384();
    $private = $generator->createPrivateKey();

    $adapter = EccFactory::getAdapter();

    $privateKeySerializer = new PemPrivateKeySerializer(new DerPrivateKeySerializer($adapter));
    $privateKey = $privateKeySerializer->serialize($private);

    $public = $private->getPublicKey();
    $publicKeySerializer = new PemPublicKeySerializer(new DerPublicKeySerializer($adapter));
    $publicKey = $publicKeySerializer->serialize($public);

    $hashPrivateKey = Keccak::hash($privateKey . time() . $entropy, 256);
    $hashPublicKey = Keccak::hash($publicKey . time() . $entropy, 256);

    return [
        'private' => $hashPrivateKey,
        'public' => $hashPublicKey,
        //'address' => '0x' . substr($hashPublicKey, 24),
        'address' => $this->checksum('0x' . substr($hashPublicKey, 24)),
    ];
}

/**
 * @param string $hashPublicKey
 * @return string
 * @throws \Exception
 */
private function checksum(string $hashPublicKey)
{
    $addressHash = '0x' . Keccak::hash(substr($hashPublicKey, 2), 256);
    $checksumAddress = '0x';

    for ($i = 0; $i < 40; $i++) {
        $checksumAddress .= $this->checkIntVal($hashPublicKey, $addressHash, $i);
    }

    return $checksumAddress;
}

/**
 * @param string $hashPublicKey
 * @param $addressHash
 * @param $i
 * @return string
 */
private function checkIntVal(string $hashPublicKey, $addressHash, $i): string
{
    return intval($addressHash[$i + 2], 16) > 7 ? strtoupper($hashPublicKey[$i + 2]) : $hashPublicKey[$i + 2];
}

@amandiobm
Copy link
Author

I agree that Ethereum addresses should and they are independent of any network, but basically, all PHP libraries when you try to create a new account, the library create a request personal_newAccount to the network you're connected. Some services will allow that request, and others don't due to security issues.

But what made me wonder was, if you see on the implementation of ethereum/web3.js to create accounts. He actually creates all hashes from scratch, as you mentioned is only a random string derived from a "private key". Check the code web3.eth.accounts.create, he uses an eth-lib to call the Account.create method eth-lib(account).

So that is why I asked you If was possible to generate those address "offline" in PHP. With that implementation that I did is possible and it works.

@digitaldonkey
Copy link
Owner

I would appreciate a pull request. Sorry for delay. I'm at DrupalEruope conference.

@amandiobm
Copy link
Author

Owww, I'll try my best to add this into a PR

@digitaldonkey
Copy link
Owner

As Ethereum-PHP aims to be client independent (including services like infura.io which restrict the personal API, I like the "offline approach" as it would be most useful.

Let me know if I can help you I'd be really happy about such feature.

@digitaldonkey
Copy link
Owner

digitaldonkey commented Sep 20, 2018

We should use PHP-7 random_bytes($length) instead of time() and mingle it with the salt($entropy) so that it is kind of secure on default

https://www.sitepoint.com/randomness-php-feel-lucky

@erdemozturk52
Copy link

Hey @digitaldonkey, I managed to create address "offline". The code is based on that post that I sent to you, and also based on the implementation of ethereum/web3.js.

I used two dependencies to reach my goal. kornrunner/php-keccak, and mdanter/ecc.

/**
 * @param null $entropy
 * @return array
 * @throws \Exception
 */
public function generateAddress($entropy = '')
{
    $generator = EccFactory::getNistCurves()->generator384();
    $private = $generator->createPrivateKey();

    $adapter = EccFactory::getAdapter();

    $privateKeySerializer = new PemPrivateKeySerializer(new DerPrivateKeySerializer($adapter));
    $privateKey = $privateKeySerializer->serialize($private);

    $public = $private->getPublicKey();
    $publicKeySerializer = new PemPublicKeySerializer(new DerPublicKeySerializer($adapter));
    $publicKey = $publicKeySerializer->serialize($public);

    $hashPrivateKey = Keccak::hash($privateKey . time() . $entropy, 256);
    $hashPublicKey = Keccak::hash($publicKey . time() . $entropy, 256);

    return [
        'private' => $hashPrivateKey,
        'public' => $hashPublicKey,
        //'address' => '0x' . substr($hashPublicKey, 24),
        'address' => $this->checksum('0x' . substr($hashPublicKey, 24)),
    ];
}

/**
 * @param string $hashPublicKey
 * @return string
 * @throws \Exception
 */
private function checksum(string $hashPublicKey)
{
    $addressHash = '0x' . Keccak::hash(substr($hashPublicKey, 2), 256);
    $checksumAddress = '0x';

    for ($i = 0; $i < 40; $i++) {
        $checksumAddress .= $this->checkIntVal($hashPublicKey, $addressHash, $i);
    }

    return $checksumAddress;
}

/**
 * @param string $hashPublicKey
 * @param $addressHash
 * @param $i
 * @return string
 */
private function checkIntVal(string $hashPublicKey, $addressHash, $i): string
{
    return intval($addressHash[$i + 2], 16) > 7 ? strtoupper($hashPublicKey[$i + 2]) : $hashPublicKey[$i + 2];
}

Not Working This Code.

Private key and address incompatible.

Sample Output:

array (size=3)
'private' => string '9343ae8f689ccceb68687a18c600395ed48559f4a12d7874a438ba71fb8d8f95' (length=64)
'public' => string '940cddcbd554ec4ab0dc6262c4a44f69ee7371336a1f1845eb12f943b0b20dc6' (length=64)
'address' => string '0xc4a44f69ee7371336a1f1845eb12f943b0b20dc6' (length=42)

True:
Private Key: 9343ae8f689ccceb68687a18c600395ed48559f4a12d7874a438ba71fb8d8f95
Address : 0x28428b4f9631178408E7c99EbE7FD7A67811296C

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants