Summary
The code in the question theoretically should not run, as the private key is in hex format and the call to new BigInteger(senderPrivKey)
to parse the hex string without the 16
radix specified would result in a thrown exception.
When the code is adjusted to use new BigInteger(senderPrivKey, 16)
specifying the base 16 radix, the public key is generated as expected.
The Details
Here is a working example. Save it as TestKey.java, compile and run it.
import java.math.BigInteger;
import org.ethereum.crypto.ECKey;
import org.spongycastle.util.encoders.Hex;
public class TestKey {
public static void main(String[] args) {
String senderPrivKey = "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4";
BigInteger pk = new BigInteger(senderPrivKey, 16);
System.out.println("Private key: " + pk.toString(16));
ECKey key = ECKey.fromPrivate(pk);
System.out.println("Public key: " + Hex.toHexString(key.getAddress()));
}
}
And the output when running it:
Private key: c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4
Public key: cd2a3d9f938e13cd947ec05abc7fe734df8dd826
I have used the following maven dependency:
<dependency>
<groupId>org.ethereum</groupId>
<artifactId>ethereumj-core</artifactId>
<version>1.1.0-RELEASE</version>
<!-- <type>zip</type> -->
</dependency>
I don't know how your code ran, because when I change the following line in the source code above to match your code, the BigInteger(...)
constructor is expecting to parse a base 10 number rather than a base 16 number :
BigInteger pk = new BigInteger(senderPrivKey);
And I get the following exception:
Exception in thread "main" java.lang.NumberFormatException: For input string: "c"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.math.BigInteger.<init>(BigInteger.java:461)
at java.math.BigInteger.<init>(BigInteger.java:597)
at TestKey.main(TestKey.java:14)
ethereumjs-wallet can be used to get public key from private key:
> const hdkey = require('ethereumjs-wallet/hdkey')
> const privateKey = hdkey.fromMasterSeed('random')._hdkey._privateKey
> const Wallet = require('ethereumjs-wallet')
> const wallet = Wallet.fromPrivateKey(privateKey)
> wallet.getPublicKeyString()
'0x11f2b30c9479ccaa639962e943ca7cfd3498705258ddb49dfe25bba00a555e48cb35a79f3d084ce26dbac0e6bb887463774817cb80e89b20c0990bc47f9075d5'
> wallet.getPublicKey()
<Buffer 11 f2 b3 0c 94 79 cc aa 63 99 62 e9 43 ca 7c fd 34 98 70 52 58 dd b4 9d fe 25 bb a0 0a 55 5e 48 cb 35 a7 9f 3d 08 4c e2 6d ba c0 e6 bb 88 74 63 77 48 ... >
Another option is to use ethereumjs-util (which is used by ethereumjs-wallet internally):
> const util = require('ethereumjs-util')
> util.privateToPublic(privateKey)
<Buffer 11 f2 b3 0c 94 79 cc aa 63 99 62 e9 43 ca 7c fd 34 98 70 52 58 dd b4 9d fe 25 bb a0 0a 55 5e 48 cb 35 a7 9f 3d 08 4c e2 6d ba c0 e6 bb 88 74 63 77 48 ... >
Yet another option is secp256k1:
> const secp256k1 = require('secp256k1')
> secp256k1.publicKeyCreate(privateKey, false).slice(1)
<Buffer 11 f2 b3 0c 94 79 cc aa 63 99 62 e9 43 ca 7c fd 34 98 70 52 58 dd b4 9d fe 25 bb a0 0a 55 5e 48 cb 35 a7 9f 3d 08 4c e2 6d ba c0 e6 bb 88 74 63 77 48 ... >
slice(1)
is to drop type byte which is hardcoded as 04
ethereum.
Best Answer
You need to hash the bytes of the public key (not the public key string).
In Javascript https://runkit.com/embed/2w4f7dvkz2lg
Note how the public key is put in a Buffer.