*Low-tech guide to generating a bitcoin private key seed - featuring less conventional use of the Coldcard hardware wallet.*

The mnemonic seed phrase commonly used to represent bitcoin wallets usually consists of 24 words. How do we generate such a seed while placing minimal trust in any computer, even the Coldcard wallet itself?

The Coldcard has a mode for generating a seed using entropy from dice throws - but I didn't want to rely on that entropy processing, I wanted a more tactile way of generating it.

The 24 word phrase actually corresponds to 256 bits of entropy + an 8-bit checksum. Those 264 bits together mean that each of these 24 words correspond to 11 bits. Since the checksum is actually one byte of the SHA-256 hash of the rest of the bits, we cannot generate it by hand in a reasonable amount of time (see SHA-256 algorithm on Wikipedia). But that is where a Coldcard or similar tool comes in. When importing the words of a seed phrase it will prompt you on the last word to select one of 8 possible words, this will come in handy...

We can generate the first 256 bits using dice, in my case using two regular 6-sided dice to generate 2 bits at a time (that is 128 throws). Since 6 is not a power of 2 number, we fall back to even numbers (2,4,6) are 0 and odd numbers (1,3,5) are 1. It's important to decide beforehand on the ordering of the dice/bits to avoid inserting unconscious skewing of the random distribution. In my case I chose to have the red big dice correspond to the left bit and the small green dice correspond to the right bit. If you have identical dice, you can put them in a transparent box, shake them and then let them rest against one side, reading them in the same order every time.

Take a paper and designate 24 lines (here with 2 columns):

Write down ones and zeroes for each set of dice throws, 11 bits per line (only 3 bits for the 24th line), like so:

It makes the next step easier if you group the binary digits in groups of 3-4-4 as above. Since 11 is a prime number and I was using more than one dice, I let the overflowing digit from the last dice roll feed over to the next line. After completing this step you should end up with:

Now we will use our knowledge of binary-hexadecimal interchangeability to convert from base 2 to base 16.

bin | hex |
---|---|

0000 | 0 |

0001 | 1 |

0010 | 2 |

0011 | 3 |

0100 | 4 |

0101 | 5 |

0110 | 6 |

0111 | 7 |

1000 | 8 |

1001 | 9 |

1010 | A |

1011 | B |

1100 | C |

1101 | D |

1110 | E |

1111 | F |

11 bits per word means the standardized word list contains 2^{11} = 2048 words. One word on each line, sorted alphabetically and numbered hexadecimally gives us the following:

hex | word |
---|---|

0x000 | abandon |

0x001 | ability |

0x002 | able |

... | ... |

0x579 | quality |

... | ... |

0x7FE | zone |

0x7FF | zoo |

Go here to download the full list, numbered in hex.

(Since we are starting from 0 instead of 1, the last line is numbered 0x7FF, which is 2048-1 => 2047).

The set of dice rolls producing "(0)101 0111 1001" for the first word maps to "5 7 9" in hex, corresponding to "quality":

Up until now, the process only requires using pen, paper, dice and using a computer to scroll up and down to look up words. The 2048 word list could be printed out in case you are afraid that the computer has been compromised, but they wouldn't know the precise word you were scrolling to look up anyway.

Enter the 23 full words into the Coldcard seed import section, and then on the last screen select the word that corresponds to the 3 bits on the 24th line. If your 3 last bits were 101 for example, that would map to the 5th word. I'm not 100% sure of the ordering, but the 24th word includes both the last 3 bits of entropy and the 8-bit checksum, and the Coldcard only presents words corresponding to valid checksums. 3 bits gives us values from 0-7, which gives us 8 possible words.

Now you have a low-tech, human-generated mnemonic seed phrase. Treasure it and keep it secret!

Credits go to Arman the Parman for his DIY Bitcoin Private Key Project article. Differences from his original:

- Convert binary to hexadecimal instead of decimal, which avoids having to do a bunch of math.
- Use an air-gapped single-purpose device like the Coldcard to calculate the last word. He uses a computer and a shell (with history?) to input the entropy and calculate the checksum. If I didn't already own a Coldcard or similar, I would probably use Tails OS without an internet connection.
- My article is less educational and verbose.

Also somewhat inspired by Crypto Guide in how to order identical dice to avoid unconscious skewing of the random distribution: https://youtu.be/j5nejoEGWFw

Standard used: Bitcoin Improvement Proposal number 39 - "Mnemonic code for generating deterministic keys" (original word list file)

You can also use dice to generate a PIN number, first in binary, then converting it to decimal with similar pen & paper math as in Arman's article. For long PINs, beware of low entropy in the leftmost digits though.

I played with the idea of using base 6 since we are using dice. That would be 0-5, 6 on the dice-face counts as 0. Numbering the word list in base 6 results in 0-13251, decimal 2048 is not divisible by 6. The first digit would be either 0 or 1, the second would be one of 0,1,2,3 and the last 3 digits would be full dice rolls, 0-5 - except if you are at the very end of the wordlist (1325?), then the rightmost digit is either 0 or 1. When we want a 0 or a 1 we could just fall back to even/odd numbers, but for the second digit in the 0-3 range one would just have to re-roll to get within range, other strategies like modulo would skew the distribution. Absolute best case you get something like 24 * 2.5 = 60 rolls with two dice, but statistically you will add a lot of re-rolls on top.