I was looking for a technique to store a wallet seed. Because if somebody find your seed that person can steal the bitcoins. I found a way to split the seed in two parts for cold storage.
- the technique can be use for any seed. Any number of words in the seed or dictionary. On a software or hardware wallet.
- encryption and decryption is simple and can be done with pen and paper if you want. I also made a python scrypt to encrypt (split) and decrypt (reassamble).
- Both parts contains only words and looks like an ordinary seed. No need to write a series of random characters that is error prone.
- The technique is based on the One time pad encryption.
I will show you how it's done manually. First you need a seed:
park color slice trade remove depend meadow bus clock curious where where
You create a second seed that will be use for encryption. I call that seed : "encryption seed A". It's one of the two part of the splitted seed. On electrum I use the make_seed command to generate it:
goddess clump renew require timber pitch loan bless sock hint ecology finish
To generate the second part that I call "encryption seed B". You need the dictionary file used by your wallet. Most of the time wallets are using
https://raw.githubusercontent.com/bitcoin/bips/master/bip-0039/english.txt. For each words in your seed and in your "encryption seed A". You need the word number in the dictionary. The first word is number 1 and the last one is 2048.
seed:
park color slice trade remove depend meadow bus clock curious where where
1282 365 1627 1845 1455 471 1101 247 347 431 2002 2002
encryption seed A:
goddess clump renew require timber pitch loan bless sock hint ecology finish
801 354 1457 1464 1809 1324 1048 189 1648 862 560 696
Finally to obtain "encryption seed B" for each word you need to calculate index(word_seed) - index(word_encryption_a) % 2048.
ecryption seed B:
481 11 170 381 1694 1195 53 58 747 1617 1442 1306
destroy accident best cook stable nice allow also frost sketch reform person
Now you can write "encryption seed A" and "encryption seed B" on separate piece of paper. Before deleting you seed you should test decryption. You just need encryption seed A and B and calculate index(word_encryption_a) + index(word_encryption_b) % 2048. Now you can safely delete your seed and hide both encryption seeds in separate locations.
Here is the Python script that does the splitting and reassambly:
#!/usr/bin/python3
import sys, getopt
with open('english.txt') as file:
words = file.read().splitlines()
def validate_seed(seed):
for word in seed:
if word not in words:
print(word, 'is not a valid BIP39 word')
sys.exit(1)
def usage():
print('If you want to crypt a seed: crypt_seed.py')
print('If you want to decrypt a seed: crypt_seed.py -d')
if len(sys.argv) == 2:
arg = sys.argv[1]
if arg in ('-h', '--help'):
usage()
elif arg in ("-d", "--decrypt"):
encryption_seed_a = input('Enter your encryption seed A: ').split()
validate_seed(encryption_seed_a)
encryption_seed_b = input('Enter your encryption seed B: ').split()
validate_seed(encryption_seed_b)
seed = ''
for i,word_a in enumerate(encryption_seed_a):
index_a = words.index(word_a)
index_b = words.index(encryption_seed_b[i])
index_seed = (index_a + index_b) % 2048
word_seed = words[index_seed]
seed += word_seed + ' '
print('Your seed is: ', seed)
else:
print('Unrecognized argument')
usage()
else:
seed = input('Enter your seed: ').split()
validate_seed(seed)
encryption_seed_a = input('Enter an encryption seed A: ').split()
validate_seed(encryption_seed_a)
encryption_seed_b = ''
for i,word_seed in enumerate(seed):
index_seed = words.index(word_seed)
index_a = words.index(encryption_seed_a[i])
index_b = (index_seed - index_a) % 2048
word_b = words[index_b]
encryption_seed_b += word_b + ' '
print('Your encryption seed B is: ', encryption_seed_b)