What encoding or format is the private key in Dumpprivkey?

5

3

I'm trying to use the results of Dumpprivkey to sign a message outside of the QT client, however I'm either having a problem signing or extracting the real value of the key.

What encoding, endian, or format is Dumpprivkey in?

I assume it's Base58 encoded...

goodguys_activate

Posted 2014-02-08T17:02:03.477

Reputation: 11 898

Answers

6

The format is base58check, with 0x80 as version byte (for Bitcoin mainnet, at least), and an optional suffix 0x01 byte to indicate that the corresponding public key is compressed. So combined:

  • base58(0x80 | 32-byte big-endian secret parameter | checksum) for uncompressed public keys
  • base58(0x80 | 32-byte big-endian secret parameter | 0x01 | checksum) for compressed public keys

Pieter Wuille

Posted 2014-02-08T17:02:03.477

Reputation: 54 032

1

It is Base58 encoded with an initial version byte and 4 checksum bytes on the end. The version byte indicates the network (production network=128 and test network=239). The checksum is the first 4 bytes of the double SHA-256 hash of the version and key.

Here is some Java code which creates the private key from the dumped format:

public DumpedPrivateKey(String string) throws AddressFormatException {
        //
        // Decode the private key
        //
        byte[] decodedKey = Base58.decodeChecked(string);
        int version = (int)decodedKey[0]&0xff;
        if (version != Parameters.DUMPED_PRIVATE_KEY_VERSION)
            throw new AddressFormatException(String.format("Version %d is not correct", version));
        //
        // The private key length is 33 for a compressed public key, otherwise it is 32
        //
        if (decodedKey.length == 33+1 && decodedKey[33] == (byte)1) {
            isCompressed = true;
            privKeyBytes = Arrays.copyOfRange(decodedKey, 1, decodedKey.length-1);
        } else if (decodedKey.length == 32+1) {
            isCompressed = false;
            privKeyBytes = Arrays.copyOfRange(decodedKey, 1, decodedKey.length);
        } else {
            throw new AddressFormatException("Private key length is incorrect");
        }
    }
    public static byte[] decodeChecked(String string) throws AddressFormatException {
        //
        // Decode the string
        //
        byte[] decoded = decode(string);
        if (decoded.length < 4)
            throw new AddressFormatException("Decoded string is too short");
        //
        // Verify the checksum contained in the last 4 bytes
        //
        byte[] bytes = Arrays.copyOfRange(decoded, 0, decoded.length-4);
        byte[] checksum = Arrays.copyOfRange(decoded, decoded.length-4, decoded.length);
        byte[] hash = Arrays.copyOfRange(Utils.doubleDigest(bytes), 0, 4);
        if (!Arrays.equals(hash, checksum))
            throw new AddressFormatException("Checksum is not correct");
        //
        // Return the result without the checksum bytes
        //
        return bytes;
    }

ScripterRon

Posted 2014-02-08T17:02:03.477

Reputation: 2 023

Thanks! Can you tell me where you got this from? I need to sign a message in c# using this private key. The functional verification code is here http://stackoverflow.com/a/20400041/328397

goodguys_activate 2014-02-09T16:26:12.650

It's from my bitcoin node (which is written in Java). I can send you the Java class if you send me your e-mail address. It uses BouncyCastle 1.50 for all of the heavy lifting.ScripterRon 2014-02-10T01:10:20.730

I'm using this code here to inspire the C# work in BitcoinJ You can email me at Myname at gmail. Thanks!

goodguys_activate 2014-02-10T01:57:11.260

@makerofthings7 SentScripterRon 2014-02-10T04:13:48.003