Mini private key format: Difference between revisions

From Bitcoin Wiki
Jump to navigation Jump to search
Casascius (talk | contribs)
No edit summary
Casascius (talk | contribs)
Line 13: Line 13:


* [[Blockchain.info]]
* [[Blockchain.info]]
** Private keys can be imported and coins sent to another address immediately upon import without needing to wait for any confirmations.  Even after import, funds remain associated with the private key until they are actually spent to a different address.
* [[Strongcoin]]
* [[Strongcoin]]
* [[Armory]]
* [[Armory]]
* [[Mt. Gox]]
* [[Mt. Gox]]
** Mt. Gox sweeps the funds to a secondary address, and then a user must wait for six confirmations before the funds will appear in the Mt. Gox account.  Removing the imported bitcoins from the Mt. Gox account is treated as a bitcoin withdrawal and counts against daily/monthly limits.  Mt. Gox also permanently remembers any imported private key and automatically sweeps any future funds sent to it into the user's Mt. Gox account.


The current mainline ("Satoshi") client cannot currently be used to import minikeys.
The current mainline ("Satoshi") client cannot currently be used to import minikeys.

Revision as of 04:48, 12 July 2012

QR codes of the same private key, in mini versus regular private key format. Both codes have the same dot density and error correction level, but the mini key is 57% of the full code's size.

The mini private key format is a method of encoding a Bitcoin private key in as few as 30 characters so that it can be embedded in a small space. This private key format was first used in Casascius physical bitcoins, and is also favorable for use in QR codes. The fewer characters encoded in a QR code, the lower dot density can be used, as well as more dots allocated to error correction in the same space, significantly improving readability and resistance to damage. The mini private key format offers its own built-in check code as a small margin of protection against typos.

An example key using this encoding is Sz9vkwiuc5ghNWKcemKoNi66pJ6AgM.

Usage on a physical bitcoin

The way it might appear within a physical bitcoin is on a round card printed as follows:

Sz9v
kwiuc
5ghNWK
cemKoN
i66pJ
6AgM

Import

Mini private keys can be imported through the following clients/services:

  • Blockchain.info
    • Private keys can be imported and coins sent to another address immediately upon import without needing to wait for any confirmations. Even after import, funds remain associated with the private key until they are actually spent to a different address.
  • Strongcoin
  • Armory
  • Mt. Gox
    • Mt. Gox sweeps the funds to a secondary address, and then a user must wait for six confirmations before the funds will appear in the Mt. Gox account. Removing the imported bitcoins from the Mt. Gox account is treated as a bitcoin withdrawal and counts against daily/monthly limits. Mt. Gox also permanently remembers any imported private key and automatically sweeps any future funds sent to it into the user's Mt. Gox account.

The current mainline ("Satoshi") client cannot currently be used to import minikeys.

Decoding

The private key encoding consists of 30 alphanumeric characters from the base58 alphabet used in Bitcoin. The first of the characters is always the uppercase letter S.

A simple test must be performed to determine which method shall be used:

  1. Add a question mark to the end of the mini private key string.
  2. Take the SHA256 hash of the entire string. However, we will only looking at the first two bytes of the result.
  3. If the first byte is 00, the string is a well-formed minikey. If the first byte is not 00, the string should be rejected as a minikey.

Example with SHA256

Here is an example with the sample private key Sz9vkwiuc5ghNWKcemKoNi66pJ6AgM.

The string "Sz9vkwiuc5ghNWKcemKoNi66pJ6AgM?" has a SHA256 value that begins with 00, so it is well-formed.

To obtain the full 256-bit private key, simply take the SHA256 hash of the entire string. There is no encoding for breaks in the string even if printed that way - the SHA256 should be taken of exactly thirty bytes.

SHA256("Sz9vkwiuc5ghNWKcemKoNi66pJ6AgM") = 68DD9613911D884866A613EE909A8C3B1877D47BF4B59350AA44ED1687FA5127 

This sample key in wallet export format is 5JcUEPy6ZNEU2beoyAZdPwjtZWPeiU2j2nDwMjGXWeoD87LrURL, and the corresponding Bitcoin address is 1HwWMmDFaFLDBt3XRfCce3kA1rR2Syb1W2.

Check code

The mini private key format offers a simple typo check code. Mini private keys must be generated in a "brute force" fashion, keeping only keys that conform to the format's rules. If a key is well-formed (30 Base58 characters starting with S), but fails the hash check, then it probably contains a typo.

If the SHA256 hash of the string followed by '?' doesn't result in something that begins with 0x00, the mini private key is not valid.

Creating mini private keys

Creating mini private keys is relatively simple. One program which can create such keys is Casascius Bitcoin Utility.

Mini private keys must be created "from scratch", as the conversion from mini private key to full-size private key is one-way. In other words, there is no way to convert an existing full-size private key into a mini private key.

To create mini private keys, simply create random strings that satisfy the well-formedness requirement, and then eliminate the ones that do not pass the typo check. (This means eliminating more than 99% of the candidates.) Then use the appropriate algorithm to compute the corresponding private key, and in turn, the matching Bitcoin address. The Bitcoin address can always be computed from just the private key.

It is strongly advisable to avoid using the digit "1" in minikeys unless it is being printed in such a way where a user is unlikely to mistake it for the lowercase letter "l". Few clients and redemption tools are prepared to tell the user that their entry containing the letter "l" should actually be the number "1" - rather, they will simply reject the code and may leave the user confused.

In all cases, you must use a secure cryptographic random number generator to eliminate risks of predictability of the random strings.

Casascius Series 1 coins

Casascius Series 1 Physical Bitcoins use a 22-character variant of the minikey format, instead of 30 characters. Everything is the same other than the length. To properly implement minikey redemption, services and clients MUST support the 30-character format, but MAY support the 22-character format as well. Use of the 22-character format for future applications is discouraged due to security considerations.

Python Code

The following code produces sample SHA256-based mini private keys in Python. For real-world use, random must be replaced with a better source of entropy, as the Python documentation for random states the function "is completely unsuitable for cryptographic purposes".

import random
import hashlib

BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

def Candidate():
    """
    Generate a random, well-formed mini private key.
    """
    return('%s%s' % ('S', ''.join(
        [BASE58[ random.randrange(0,len(BASE58)) ] for i in range(21)])))

def GenerateKeys(numKeys = 10):
    """
    Generate mini private keys and output the mini key as well as the full
    private key. numKeys is The number of keys to generate, and 
    """
    keysGenerated = 0
    totalCandidates = 0
    while keysGenerated < numKeys:
        try:
            cand = Candidate()
            # Do typo check
            t = '%s?' % cand
            # Take one round of SHA256
            candHash = hashlib.sha256(t).digest()
            # Check if the first eight bits of the hash are 0
            if candHash[0] == '\x00':
                privateKey = GetPrivateKey(cand)
                print('\n%s\nSHA256( ): %s\nsha256(?): %s' %
                      (cand, privateKey, candHash.encode('hex_codec')))
                if CheckShortKey(cand):
                    print('Validated.')
                else:
                    print('Invalid!')
                keysGenerated += 1
            totalCandidates += 1
        except KeyboardInterrupt:
            break
    print('\n%s: %i\n%s: %i\n%s: %r\n%s: %.1f' %
          ('Keys Generated', keysGenerated,
           'Total Candidates', totalCandidates,
           'Additional Security', additionalSecurity,
           'Reject Percentage',
           100*(1.0-keysGenerated/float(totalCandidates))))

def GetPrivateKey(shortKey):
    """
    Returns the hexadecimal representation of the private key corresponding
    to the given short key.
    """
    if CheckShortKey(shortKey):
        return hashlib.sha256(shortKey).hexdigest()
    else:
        print('Typo detected in private key!')
        return None

def CheckShortKey(shortKey):
    """
    Checks for typos in the short key.
    """
    if len(shortKey) != 22:
        return False
    t = '%s?' % shortKey
    tHash = hashlib.sha256(t).digest()
    # Check to see that first byte is \x00
    if tHash[0] == '\x00':
        return True
    return False