I have the feeling something is not right with the method getPrivateKeyEncoded
(which returns a DumpedPrivateKey
object) of the ECKey
class. If I attempt to recover the orginal key from the DumpedPrivateKey
object using the getKey
method, the retrieved key appears to be wrong (in the compressed case). I would be grateful if someone could tell me whether I am missing something, or whether this is a deliberate API choice etc. I attach a sample Test program to illustrate the issue:
// running bitcoinj-core-0.14.3.jar
import java.math.BigInteger;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.DumpedPrivateKey;
public class Test {
public static void checkEquals(BigInteger n1, BigInteger n2, String msg){
if(!n1.equals(n2)){
System.err.println("failure in " + msg + ":");
System.err.println("n1 = " + n1.toString(16));
System.err.println("n2 = " + n2.toString(16));
System.exit(1);
}
}
public static void main(String[] args){
String mainAsString = NetworkParameters.ID_MAINNET;
String testAsString = NetworkParameters.ID_REGTEST;
NetworkParameters mainNet = NetworkParameters.fromID(mainAsString);
NetworkParameters testNet = NetworkParameters.fromID(testAsString);
// compressed key
ECKey k1 = new ECKey();
// same key uncompressed
ECKey k2 = k1.decompress();
// common private secret
BigInteger secret = k1.getPrivKey(); // same as k2.getPrivKey()
// 4 possible types of WIF
String wifMain1 = k1.getPrivateKeyAsWiF(mainNet); // main, compressed
String wifMain2 = k2.getPrivateKeyAsWiF(mainNet); // main, uncompressed
String wifTest1 = k1.getPrivateKeyAsWiF(testNet); // test, compressed
String wifTest2 = k2.getPrivateKeyAsWiF(testNet); // test, uncompressed
// creating corresponding DumpedPrivateKey
DumpedPrivateKey dpkMain1 = DumpedPrivateKey.fromBase58(null, wifMain1);
DumpedPrivateKey dpkMain2 = DumpedPrivateKey.fromBase58(null, wifMain2);
DumpedPrivateKey dpkTest1 = DumpedPrivateKey.fromBase58(null, wifTest1);
DumpedPrivateKey dpkTest2 = DumpedPrivateKey.fromBase58(null, wifTest2);
// reconstructing ECKey from DumpedPrivateKey
ECKey keyMain1 = dpkMain1.getKey();
ECKey keyMain2 = dpkMain2.getKey();
ECKey keyTest1 = dpkTest1.getKey();
ECKey keyTest2 = dpkTest2.getKey();
// Testing all is fine (should also check compression status)
checkEquals(secret, keyMain1.getPrivKey(), "test1");
checkEquals(secret, keyMain2.getPrivKey(), "test2");
checkEquals(secret, keyTest1.getPrivKey(), "test3");
checkEquals(secret, keyTest2.getPrivKey(), "test4");
// so far so good...
// now creating DumpedPrivateKey objects from getPrivateKeyEncoded
dpkMain1 = k1.getPrivateKeyEncoded(mainNet);
dpkMain2 = k2.getPrivateKeyEncoded(mainNet);
dpkTest1 = k1.getPrivateKeyEncoded(testNet);
dpkTest2 = k2.getPrivateKeyEncoded(testNet);
// again reconstructing ECKey from DumpedPrivateKey
keyMain1 = dpkMain1.getKey();
keyMain2 = dpkMain2.getKey();
keyTest1 = dpkTest1.getKey();
keyTest2 = dpkTest2.getKey();
// testing is successful for uncompressed keys ...
checkEquals(secret, keyMain2.getPrivKey(), "test6");
checkEquals(secret, keyTest2.getPrivKey(), "test7");
// ... but fails for compressed keys
checkEquals(secret, keyMain1.getPrivKey(), "test8");
checkEquals(secret, keyTest1.getPrivKey(), "test9");
// the output shows a trailing suffix byte 0x01
/*
failure in test8:
n1 = 3e27a3956811801724857245ae78dd8ba1ce3df60da2bb00a782cee66ed640ee
n2 = 3e27a3956811801724857245ae78dd8ba1ce3df60da2bb00a782cee66ed640ee01
*/
}
}