To help the users who have imported private keys from blockchain.info we've written a utility that checks the integrity of the private keys. It recalculates the address from scratch from the private key and cross checks against the address in the receiving addresses.
It will appear in "Tools | Check Private Keys" and will basically be:
This will not help all cases because the old import code was outright broken:
snippet from old BCI import code
public static ECKey decodeBase58PK(String base58Priv) throws Exception {
byte[] privBytes = Base58.decode(base58Priv);
// Prepend a zero byte to make the biginteger unsigned
byte[] appendZeroByte = concat(new byte[1], privBytes);
ECKey ecKey = new ECKey(new BigInteger(appendZeroByte));
return ecKey;
}
The above only works if the key was meant to produce an uncompressed key. If it was meant to be a compressed key (note that blockchain.info does not use the satoshi dumped wallet key format, they use the naked private key base58 encoded lacking the compressed/uncompressed flag) this will
always produce an uncompressed key!
and on top of that it will always produce a
valid uncompressed ECKey (always matching private and public because it does not use that other constructor that also sets the public key).
This means the people who have had compressed keys in BCI and imported them now have the correct private keys but the wrong bitcoin addresses.
---
This is how my own import tool currently handles it (it also takes into account the address from the json):
Xtend code:
/**
* Try to produce an ECKey Object from the given arguments.
* BCI has a very uncommon way of encoding the private key, its not the
* usual dumped private key format of the Satoshi client, its just base58 of
* the key bytes. Most importantly it is also lacking the information whether
* it is meant to produce a compressed or uncompressed public key. For this
* we try both and compare with the supplied bitcoin address, if none of
* them match (which should never happen) then this will throw an exception.
*
* @param base58Priv String containing the BCI encoded private key
* @param addr String containing the bitcoin address
* @return a new ECKey object representing this key
* @throws Exception if the input can not be interpreted in any meaningful way
*/
private def ECKey decodeBase58PK(String base58Priv, String addr) throws Exception {
val privBytes = Base58.decode(base58Priv);
var ecKey = new ECKey(new BigInteger(1, privBytes), null, false);
if (ecKey.toAddress(new MainNetParams).toString.equals(addr)){
log.debug("{} has uncompressed key", addr)
return ecKey;
} else {
ecKey = new ECKey(new BigInteger(1, privBytes), null, true);
if (ecKey.toAddress(new MainNetParams).toString.equals(addr)){
log.debug("{} has compressed key", addr)
return ecKey;
} else {
val err = addr + " and private key don't match, neither compressed nor uncompressed"
log.error(err)
throw new Exception(err)
}
}
}