5

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...

5

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
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;
    }

  • 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 stackoverflow.com/a/20400041/328397 – random65537 Feb 9 '14 at 16:26
  • 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 Feb 10 '14 at 1:10
  • I'm using this code here to inspire the C# work in BitcoinJ You can email me at Myname at gmail. Thanks! – random65537 Feb 10 '14 at 1:57
  • @makerofthings7 Sent – ScripterRon Feb 10 '14 at 4:13

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.