2

Based on the following link: https://en.bitcoin.it/wiki/Wallet_import_format , a private key of 256 bits gets transformed into a WIF address that is stored in the wallet.

However, my question here is how did we convert step 6 into step 7? In step 6, the address consists of 74 hexadecimals characters (or 74*4= 296 bits). If we convert this 296 bits address using the code58, we need to divide 296 bits by 6.. ? I believe that some details are not mentioned, any ideas?

5 Answers 5

1

StephenM347's answer is very good, but there is one little detail he got wrong. I'd post this as a comment to his answer, but I don't have enough reputation.

Stephen said:

For example, there is no O character, because there is already a 0 (zero) character, and the two could be confused really easily.

The wiki says:

A set of 58 alphanumeric symbols consisting of easily distinguished uppercase and lowercase letters (0OIl are not used)

A lowercase "o" is used, but the uppercase "O" and the number "0" are both excluded from base 58.

2
  • You are right, although I don't see why it the encoding couldn't have used at least one of the two symbols 0/O, providing the other was excluded to prevent confusion. Still, I think this is not really an answer to the question. Suggesting an edit to my original answer since this is is such a small detail, as Nick Odell has done, is a better way to go. Since you are new, your edit will have to be reviewed before it is accepted. Welcome to the bitcoin stack exchange, though, hope you can apply that close attention to detail in future answers!
    – morsecoder
    Mar 28, 2015 at 5:25
  • Ah, thanks for the tip. I didn't realise that I could suggest edits to other peoples' posts. I think the idea of avoiding both is to make it less likely that somebody with no knowledge of base 58 doesn't assume one symbol is the other when copying a WIF key down; they also avoid both the uppercase "I" and lowercase "l". Neither of them looks particularly similar to the number "1", but they could both be easily confused with each other.
    – JNCF
    Mar 28, 2015 at 17:01
1

You're basically wondering how Base58 encoding works. This site gives a good overview but I will list the details here as well with a more concrete example. For this example, I'll just talk about the encoding, but the version byte (prepended) and checksum bytes (appended) do get added before this encoding is done. This prepending/appending just changes the base data before encoding. The below is how the data gets encoded.

Let's say I have this simple encoding called Base4 encoding. In my encoding:

  0->A
  1->B
  2->C
  3->D
If I have the number 134 (1000 0110 or 0x86) and I want to encode it in Base4, then what I do is repeatedly divide by 4 and use the encoding. Like so:

134 / 4 = 33 remainder 2 -> C
          /
   -------
  |
 33 / 4 =  8 remainder 1 -> B
          /
   -------
  |
  8 / 4 =  2 remainder 0 -> A
          /
   -------
  |
  2 / 4 =  0 remainder 2 -> C

So the Base4 encoding for this byte would be "CABC". Bitcoin does the same thing, but using 58 numbers instead of 4, and a different character for each. The characters chosen in the Base58 encoding are just to avoid confusion when humans transpose the key. For example, there is no I character, because there is already a 1 character, and the two could be confused really easily.

There's just one more thing that's a little tricky. If I were encoding the data 0x0086, I might want the encoding to be slightly different than the above encoding for 0x86 to show that I had an extra 0x00 byte at the beginning. To do this, all you do is add extra data at the left side of the encoding. So, in our Base4, 0x0086 is encoded as ACABC. Similarly 0x0000 0086 is encoded as AAACABC. In standard bitcoin addresses, the version byte prefix is 0x00, and 0x00 is encoded as a 1, so addresses always start with a 1.

4
  • Quick query; when you say add 0x00 what does that mean? I know 0x is shorthand for hexadecimal but when you say add 0x00 are you saying add 00 to the start of the hex value? If so why? Aug 29, 2014 at 8:38
  • 0x00 means a null byte. Aug 29, 2014 at 11:30
  • Right, 0x00 is just shorthand for the byte: 0000 0000. Base58 encoding is just for encoding some number of bytes.
    – morsecoder
    Aug 29, 2014 at 12:36
  • 'Adding' might have made it unclear. For any hex string you are encoding: prefix || hex || checksum of first two parts. ANYTHING that is base58 encoded for copy/pasting does this, with a different prefix byte used for each thing you want to represent. BTC addresses are prefixed with 0x00. Private keys are prefixed by 0x80. P2SH addresses are prefixed by 0x05.
    – karimkorun
    Mar 27, 2015 at 16:44
1

Here's an example of how to create a WIF with a private key using Python. It follows the docs and I've commented the code to make it enough to follow.

import binascii, hashlib, base58

# alias method
decode_hex = binascii.unhexlify

# wallet import format key - base58 encoded format
def gen_wif_key(private_key):
    # prepended mainnet version byte to private key
    mainnet_private_key = '80' + private_key

    # perform SHA-256 hash on the mainnet_private_key
    sha256 = hashlib.sha256()
    sha256.update( decode_hex(mainnet_private_key) )
    hash = sha256.hexdigest()

    # perform SHA-256 on the previous SHA-256 hash
    sha256 = hashlib.sha256()
    sha256.update( decode_hex(hash) )
    hash = sha256.hexdigest()

    # create a checksum using the first 4 bytes of the previous SHA-256 hash
    # append the 4 checksum bytes to the mainnet_private_key
    checksum = hash[:8]
    hash = mainnet_private_key + checksum

    # convert mainnet_private_key + checksum into base58 encoded string
    return base58.b58encode( decode_hex(hash) )
0

To convert command-line given string to WIF, where the parameter could be hex number or any rational string, you can use this script to get one conversion:

#!/usr/bin/env python3
import base58
import hashlib
import sys

def b58(hex):
    return base58.b58encode_check(hex)

def sha256(hex):
    return hashlib.sha256(hex).digest()

def main():
    k = sha256(str(sys.argv[1]).encode('utf-8'))
    extend = '80' + k.hex()
    print(b58(bytes.fromhex(extend)).decode('utf-8'))

if __name__ == '__main__':
    main()

Save the above file as priv2wif.py and run with 1 parameter. If your string have spaces in it, put whole string into "".

For massive conversion you can use second script in the same folder:

#!/usr/bin/env bash
> output.txt
while IFS= read -r p; do
    ./priv2wif.py "$p" >> output.txt
    echo -n .
done < "input.txt"

Save this file with no extension. You should make input.txt file with one string per line (watch out for CR/LF, as you should use LF only //Linux//) and after running the script you will get all your WIF keys in output.txt one per line.

0

simplest way

from bit import Key

# Import wif format:
privKey = Key.('L1VotKmtZRLZSnSPhLhQxfts2aqBMru2APTs4Yuc8TYJ4jNhQoGB')



# Export hex format:

privKey = Key.to_hex()

# Export int format:

privKey = Key.to_int()


# Export to bytes
privKey = Key.to_bytes()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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