Description
This recipe describes a method for storing bitcoin on paper, using an offline Raspberry Pi computer to perform the necessary computation.
Contents
- Description
- Contents
- Brief Summary
- Downloadable Assets
- Notes
- Further Work
- Equipment
- Recipe
Brief Summary
Using an offline Raspberry Pi to perform the necessary computation, complete the following tasks:
- generate a Bitcoin private key
- generate a Bitcoin address from the private key
- test the address by transferring some bitcoin into and out of it
- transfer some bitcoin into the address for long-term storage
- store the private key on paper
Downloadable Assets
The assets listed here are all assets of other articles.
List of assets:
1) bitcoin_functions.py
2) bjorn_edstrom_ripemd160.py
3) convert_dice_rolls_to_hex_bytes_2.py
4) create_nonstandard_transaction.py
5) create_transaction.py
6) display_hex_bytes.py
7) ecdsa-0.10.tar.gz
8) generate_bitcoin_address_3.py
9) nonstandard_bitcoin_functions.py
10) nonstandard_transaction.py
11) pypy_sha256.py
12) transaction.py
Asset 1: A library of functions for handling standard Bitcoin data types.
bitcoin_functions.py [paywalled]
Asset 2: An implementation of RIPEMD-160, written by Björn Edström.
bjorn_edstrom_ripemd160.py [paywalled]
Asset 3: A script that converts dice roll results into bytes.
convert_dice_rolls_to_hex_bytes_2.py [paywalled]
Asset 4: A script that creates and signs a nonstandard Bitcoin transaction with one standard P2PKH input and one nonstandard P2SH output.
create_nonstandard_transaction.py [paywalled]
Asset 5: A script that creates and signs a standard Bitcoin transaction with one input and one output.
create_transaction.py [paywalled]
Asset 6: A script that prints a hex byte string, inserting spaces and newlines to make it more readable.
display_hex_bytes.py [paywalled]
Asset 7: A Python implementation of ECDSA cryptography, written by Peter Pearson.
ecdsa-0.10.tar.gz [paywalled]
Asset 8: A script that generates a standard Bitcoin address from a private key.
generate_bitcoin_address_3.py [paywalled]
Asset 9: A library of functions for handling nonstandard Bitcoin data types.
nonstandard_bitcoin_functions.py [paywalled]
Asset 10: A library of classes for nonstandard Bitcoin transactions.
nonstandard_transaction.py [paywalled]
Asset 11: A Python implementation of SHA256.
pypy_sha256.py [paywalled]
Asset 12: A library of classes for standard Bitcoin transactions.
transaction.py [paywalled]
List of the articles that I read in order to choose these assets:
- Recipe for generating entropy bytes using dice
- Recipe for generating a Bitcoin address
- Recipe for creating and signing a standard Bitcoin transaction
- Recipe for creating and signing a nonstandard Bitcoin transaction
- Displaying hex bytes for manual copying
Notes
Parts
- Definitions and acronyms
- History
- Flash drive security concerns
- Time estimates for manual entropy generation and manual data transfer
- The disadvantage of testing a Bitcoin address
- Miscellaneous
- Nano editor commands
Definitions and acronyms
1 satoshi = 0.00000001 bitcoin (10^(-8) bitcoin). 1 satoshi is the smallest possible amount of bitcoin.
P2PKH = Pay-To-Public-Key-Hash
P2SH = Pay-To-Script-Hash
previous_output_hash is the big-endian 32-byte double-SHA256 hash of a previous transaction.
tx = "transaction"
txid = "transaction id". It is the little-endian form of the previous_output_hash.
My working definition of a standard transaction:
- It has at least one input and at least one output.
- All input and output addresses are Pay-To-Public-Key-Hash (P2PKH).
- All input scriptSigs contain uncompressed public keys.
My working definition of a nonstandard transaction:
- It has at least one input and at least one output.
- At least one input or output address is not a standard Pay-To-Public-Key-Hash (P2PKH) address.
My working definition of a standard address:
- An uncompressed single-signature Pay-To-Public-Key-Hash (P2PKH) address.
Pay-To-Public-Key-Hash (P2PKH) addresses start with the character '1'. Example:
The address
1AGygbyEFYduWkkmZbbvirgS9kuBBMLJCP
begins with a '1' and is therefore a P2PKH address.
Pay-To-Script-Hash (P2SH) addresses begin with the character '3'. Example:
The address
328cTqexYnQRbN5Dgs12D89sYiPPvtWVbF
begins with a '3' and is therefore a P2SH address.
The "storage address" in this recipe is the address that you create on the offline Raspberry Pi. It is for secure offline storage of bitcoin.
The "destination address" in this recipe is used to receive the bitcoin that moves into and out of the storage address during validation testing. It should be an address that you control or the receiving address for your account at a Bitcoin storage service.
History
This recipe has been derived from work published in the article Storing bitcoin on an offline Raspberry Pi. In the linked project, I generated an offline address, tested it by transferring some bitcoin into and out of it (creating an offline transaction in order to do so), and stored a larger amount of bitcoin in it for a week. Additionally, the project demonstrates the creation and broadcast of a new higher-fee version of the test transaction, as the first version was never mined.
I have carefully tested each section of this recipe, but have not tested it end-to-end.
Flash drive security concerns
In this recipe, a flash drive is used to transfer the assets to the offline Raspberry Pi. This is not the most secure way to transfer data to an offline computer (various malware items have been designed to store themselves on flash drives). However, for storing bitcoin, using an offline computer and a flash drive is more secure than using an online computer, and security is always relative.
Ideally, the flash drive should only be used once to transfer all the code to the offline computer. Then, the flash drive should be destroyed, and any data produced on the offline computer should be manually copied to an online computer. This recipe outlines how to perform this manual copying.
You may prefer to use a flash drive repeatedly to transfer data back and forth between the online and offline computers, but please note that this approach is less secure than a single use of a flash drive.
For maximum security, code should only be moved onto an offline computer by manually typing it all in. This is not always possible within a useful timeframe. In the article Storing bitcoin on an offline Raspberry Pi, in the "Time taken to manually transfer transactions by typing" part of the Notes section, I estimated an upper bound of 3 years for manually copying the code used in this recipe to the offline computer. Admittedly, manually copying code would be significantly faster than manually copying hex bytes.
In practice, steadily increasing security, as and when it is reasonable and affordable to do so, is usually the most effective strategy.
Time estimates for manual entropy generation and manual data transfer
- In the article Storing bitcoin on an offline Raspberry Pi, in the "Time taken to manually transfer transactions by typing" part of the Notes section, I estimated that manually typing out a single-input single-output transaction should take about 15 minutes at most, and about 10 minutes if done quickly.
- In the same article, in the "Dice rolling results" part of the Notes section, I estimated that using 5 dice to generate 32 bytes of entropy should take about 10 minutes at most, and about 7 minutes if done quickly.
Manual data transfer rate (approximate):
2.51 bits / second
Manual entropy generation rate (approximate):
0.61 bits / second
These time estimates are only valid for those who can type without looking at the keyboard.
I found that listening to music made entropy generation and transaction copying more tolerable.
The disadvantage of testing a Bitcoin address
Testing an address means that you can be sure that you can retrieve bitcoin from it, but sacrifices some protection against the potential future discovery of a weakness in the ECDSA cryptosystem.
This trade-off is worth considering only for single-use long-term storage addresses.
For a more detailed examination of this issue, please see the "Does the hash in a Bitcoin address provide any protection?" part of the Thoughts section of the article Using a transaction to validate a Bitcoin address.
Miscellaneous
Python 2.7.x must be installed on the offline computer. The code assets used in this recipe were developed / tested under Python 2.7.13 running on Mac OS X 10.6.8 (Snow Leopard), and should run successfully on other versions of Python 2.7.
The FAT32 filesystem is very portable (i.e. is supported by many operating systems).
Several points concerning Bitcoin transactions:
- New transactions spend unspent-outputs-of-previous-transactions. These can also be called "inputs".
- The bitcoin balance of an address is the sum of the unspent outputs sent by previous transactions to this address.
- To spend bitcoin from an address, the bitcoin amount must be constructed from complete inputs. Any change can be sent in a new unspent output back to the original address or to another address that you control. Inputs cannot be broken into smaller inputs prior to spending - new inputs (larger or smaller) must be created by a new transaction.
Step (11) in the recipe says to open a terminal emulator program if the Raspberry Pi boots directly into a graphical user interface. In the previous project How I bought and stored some bitcoin [paywalled], I found that LXTerminal (a terminal emulator program) could be accessed from the Raspbian Desktop via Menu / Accessories / Terminal.
Nano editor commands
Nano editor commands and their keystroke combinations:
^G = Get Help
^X = Exit
^O = WriteOut
^J = Justify
^R = Read File
^W = Where Is
^Y = Prev Page
^V = Next Page
^K = Cut Text
^U = UnCut Text
^C = Cur Pos
^T = To Spell
Notes:
- The ^ symbol means the Ctrl ("Control") key.
- Letters are written as capitals in the keystroke combinations but in practice can be typed as either lowercase or uppercase.
- Exit = Exit the Nano editor and return to the command-line interface.
- WriteOut = Write the data in the Nano editor to a file. Press Enter to confirm the filename.
- Read File = Read a file and copy its contents into the Nano editor at the current cursor position.
- Cut Text = Delete a line of text but save it to the clipboard.
- Cur Pos = Cursor Position.
- The Backspace key deletes the character behind the current cursor position. It can be held down to delete multiple characters.
- The keystroke combination ^D (ctrl-d) deletes the character in front of the current cursor position. It can be held down to delete multiple characters.
- The arrow keys can be used to move the cursor within the editor.
Further Work
I would like to be able to transfer only a portion of the bitcoin (rather than an whole unspent output) in an offline address to another address. In order to do this, I need to be able to create transactions with two outputs - I could then set a default change output (whose destination would be the original offline address), and send only a portion of the bitcoin to the other output. This requires expansion of the existing code and careful testing.
Equipment
1) A Raspberry Pi computer.
This computer should remain offline at all times.
Details of the Raspberry Pi used during testing / development of this recipe:
- Model B+ V1.2 [circa 2014]. It has various ports, including 4 USB ports (which allows simultaneous use of a mouse, a keyboard, and a flash drive) and an HDMI port. It does not have an onboard WiFi chip.
- Peripherals: An 8GB micro SD card with an installed operating system, a Raspberry Pi power cable, a screen with a DVI port, a screen power cable, a DVI male-male connector cable, a DVI female to HDMI male converter, a USB keyboard, a USB mouse, and a plastic case customised for the Raspberry Pi Model B+.
- The installed operating system is Raspbian GNU/Linux 7 (wheezy) and the Linux kernel version is 4.1.13+. Tools: nano 2.2.6, Python 2.7.3.
- The default credentials are username = "pi" and password = "raspberry".
Ideally, the peripherals should be dedicated to the Raspberry Pi and never connected to an online computer. I suspect that it is or will become possible to attack the chips within computer peripherals.
2) An online computer.
Details of the online computer used during testing / development of this recipe:
- Aineko, a 2008 Macbook running Mac OS X 10.6.8 Snow Leopard, with Python 2.7.13 installed.
3) A USB flash drive.
Details of the USB flash drive used during testing / development of this recipe:
- 8 GB, FAT32 format, name = "NO NAME"
4) The ability to format a flash drive as FAT32.
5) A set of 5 dice and a tray with raised edges in which to roll them.
6) A pen, paper, and two sealed waterproof containers.
7) Access to several important Bitcoin tools or services.
List of necessary capabilities:
- The ability to send bitcoin to an address. You can do this by a) using a Bitcoin service that stores bitcoin and creates transactions for you, b) creating a transaction on an online computer, or c) creating a transaction on an offline computer. Option (c) is most secure, option (a) is least secure.
- The ability to look up which unspent outputs are stored in a Bitcoin address.
- The ability to look up these details about an unspent output: The txid of the original transaction that sent the unspent output to its current address, the index of the unspent output in the list of outputs in the original transaction, and the value of the unspent output. The txid is a 64-hex-character string, the index is an integer, and the value can be either in satoshi (an integer) or in bitcoin (a decimal value with up to 8 decimal places).
- The ability to check the status of a transaction (i.e. has it been mined, and if so how many blocks deep is it?)
- The ability to look up current Bitcoin network transaction fee rates.
If you don't have the ability to look up which unspent outputs are stored in a Bitcoin address, here are two workarounds:
- Workaround 1: The ability to look up the transactions that have transferred bitcoin to an address, the ability to search these transaction for the relevant output that was sent to the address, and the ability to check the status (unspent or spent) of an output.
- Workaround 2: Every time a Bitcoin transaction transfers bitcoin to one of your addresses, make a record of its txid. Have the ability to search a transaction for the relevant output that was sent to your address. Make an additional note ("spent") when you spend this output.
Recipe
1) Create project directory.
On the online computer, create a project directory.
2) Download assets.
Browse to this article, scroll to the Downloadable Assets part of this article, and download all the linked assets. Move the assets into the project directory.
List of assets:
- bitcoin_functions.py
- bjorn_edstrom_ripemd160.py
- convert_dice_rolls_to_hex_bytes_2.py
- create_nonstandard_transaction.py
- create_transaction.py
- display_hex_bytes.py
- ecdsa-0.10.tar.gz
- generate_bitcoin_address_3.py
- nonstandard_bitcoin_functions.py
- nonstandard_transaction.py
- pypy_sha256.py
- transaction.py
Note: These are all the assets that are required by subrecipes that are referenced in later steps.
3) Insert flash drive.
Insert the flash drive into a USB port on the online computer.
4) Format flash drive.
Format the flash drive as FAT32 if it is not FAT32 already. How to do this is not specified in this recipe.
5) Create transfer directory.
Create a directory on the flash drive named "transfer".
6) Copy assets to transfer directory.
Copy the assets in the project directory on the online computer into the transfer directory on the flash drive.
7) Remove flash drive.
Eject / unmount the flash drive. Physically unplug the flash drive.
8) Set up Raspberry Pi.
Set up the Raspberry Pi and its peripherals.
9) Boot Raspberry Pi.
Insert the power cable into the Raspberry Pi in order to boot it.
10) Log into Raspberry Pi.
Wait for the Raspberry Pi to finish booting and log into it.
11) Get to command-line interface on Raspberry Pi.
If the Raspberry Pi boots into a command-line interface, skip this step. If it boots into a graphical user interface, open a terminal emulator program and run the commands in this recipe in this emulator.
12) Check Python version.
Use the following command to check the version of Python.
python --version
The result must be Python 2.7.x. On the Raspberry Pi used during the development of this recipe, it is 2.7.3, which is fine. The code assets may not work as expected on e.g. Python 2.6.1.
13) Check current working directory.
Use the following command to check the current working directory on the Raspberry Pi:
pwd
The result should be:
/home/pi
14) Create work directory.
Use the following command to create a work directory named "work" on the Raspberry Pi:
mkdir work
15) Transfer assets to Raspberry Pi.
Use the following recipe to transfer the assets on the flash drive to the Raspberry Pi:
Recipe for manually mounting a USB flash drive
You can use the following command to copy the assets from the transfer directory on the flash drive into the work directory on the Raspberry Pi:
cp -r /mnt/mountpoint_directory/transfer/* work/
16) Extract ecdsa directory from ecdsa-0.10.tar.gz file.
Use the following command sequence to: Change directory to the work directory, unpack the zipped tape archive file ecdsa-0.10.tar.gz, look inside the resulting "ecdsa-0.10" directory to find the "ecdsa" directory, and copy the "ecdsa" directory into the work directory:
cd work
tar -zxvf ecdsa-0.10.tar.gz
ls -1 ecdsa-0.10
cp -r ecdsa-0.10/ecdsa ecdsa
17) Generate Bitcoin private key.
Use the following recipe to generate a Bitcoin private key (32 bytes of entropy):
Recipe for generating entropy bytes using dice
The following command will use the Nano editor to open a new file in which to record dice rolls:
nano dice_rolls.txt
As you roll the dice, type the results into the open Nano editor. I recommend 5 dice results per line, and an extra empty line after every 5 lines. This produces groups of 25 rolls, which can be easily counted. When you have finished, use the WriteOut command to write the data to a file, then use the Exit command to leave the editor.
Open the file convert_dice_rolls_to_hex_bytes_2.py in the Nano editor using this command:
nano convert_dice_rolls_to_hex_bytes_2.py
Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe. Set the variable
desired_n
to be
32
. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano. Use the following command to run convert_dice_rolls_to_hex_bytes_2.py and store its output in a text file named "private_key.txt".
python convert_dice_rolls_to_hex_bytes_2.py > private_key.txt
The following command will use the Nano editor to open the file private_key.txt:
nano private_key.txt
Read the output to see if enough entropy has been produced. If not, go back and generate more dice roll results. If there is enough entropy, delete everything that isn't the entropy value (which will be used as the private key). The Cut Text command deletes an entire line. Backspace and ^D delete one character at a time. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to check the byte length of private_key.txt:
cat private_key.txt | tr -d '\n' | wc -c
The result should be 64 (64 hex characters == 32 bytes).
The
tr -d '\n'
command removes newline characters from the data (there is one at the end). The
wc -c
command counts the number of characters in the data. Use the following command to view the private key:
cat private_key.txt
Example Bitcoin private key (64 hex characters, 32 bytes):
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
18) Derive Bitcoin address from Bitcoin private key.
Use the following recipe to derive the corresponding Bitcoin address from the Bitcoin private key:
Recipe for generating a Bitcoin address
Open the file generate_bitcoin_address_3.py in the Nano editor using this command:
nano generate_bitcoin_address_3.py
Use the Nano editor to edit the controls in generate_bitcoin_address_3.py, according to the recipe.
- Delete the existing value for the variable
private_key_hex_bytes
. Use the Read File command to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). When asked for the "File to insert from", type "private_key.txt" and press Enter. Press Backspace to delete the final newline byte. - Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to run generate_bitcoin_address_3.py and store its output in a text file named "storage_address.txt".
python generate_bitcoin_address_3.py > storage_address.txt
This may take a few seconds to finish running.
The following command will use the Nano editor to open the file storage_address.txt:
nano storage_address.txt
Delete everything that isn't the Bitcoin address. The Cut Text command deletes an entire line. Backspace and ^D delete one character at a time. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
This Bitcoin address is the "storage address".
Use the following command to view the Bitcoin address:
cat storage_address.txt
Example Bitcoin address (34 characters):
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
19) Copy storage address to online computer.
Manually copy the storage address to the online computer. Use the following sequence to do this:
- Make a copy of the storage address file:
cp storage_address.txt storage_address_tmp.txt
- Open the file storage_address_tmp.txt in the Nano editor:
nano storage_address_tmp.txt
- In the editor, add a space after every four characters.
- On the online computer, open a text file. Read and manually copy each group of four characters into the text file. Double-check each group against the original group displayed on the offline Raspberry Pi. Then remove the spaces in the address on the online computer.
- On the Raspberry Pi, use the Exit command to quit the Nano editor. Press 'N' to not save the modified data.
- Delete the temporary copy of the storage address file:
rm storage_address_tmp.txt
20) Calculate small amount of bitcoin required for testing the Bitcoin address.
Look at current Bitcoin network transaction fee rates. How to do this is not specified in this recipe. Calculate a relatively small amount of bitcoin that will be enough to cover a Bitcoin transaction fee for a small test transaction. Do this by choosing a relatively high fee rate (in satoshi / byte) and multiplying it by 225 (the approximate size in bytes of a single-input single-output Bitcoin transaction). Add some extra satoshi in order to have some room to manoeuvre. You can convert the result to bitcoin if you wish, but you can also leave it in satoshi.
21) Transfer small amount of bitcoin to storage address.
Transfer the small amount of bitcoin to the storage address. How to do this is not specified in this recipe. This small amount of bitcoin will be used to test the Bitcoin address - transferring the bitcoin out of the address again will prove that the address was correctly derived from the private key.
Record the txid of the Bitcoin transaction that executes this transfer.
Example txid:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
This txid, along with some information about the relevant unspent output, will be used later to transfer bitcoin out of the address.
22) Choose destination address.
Choose a "destination address" for the test. It should be an address that you control or the receiving address for your account at a Bitcoin storage service.
If it begins with the character '1', then it is a standard (P2PKH) address. If it begins with the character '3', then it is a nonstandard (P2SH) address.
Example standard address:
1AGygbyEFYduWkkmZbbvirgS9kuBBMLJCP
Example nonstandard address:
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
23) Generate necessary entropy for signing a Bitcoin transaction.
Use the following recipe to generate sufficient entropy for making a Bitcoin transaction signature (32 bytes of entropy):
Recipe for generating entropy bytes using dice
The following command will use the Nano editor to open a new file in which to record dice rolls:
nano dice_rolls2.txt
As you roll the dice, type the results into the open Nano editor. When you have finished, use the WriteOut command to write the data to a file, then use the Exit command to leave the editor.
Open the file convert_dice_rolls_to_hex_bytes_2.py in the Nano editor using this command:
nano convert_dice_rolls_to_hex_bytes_2.py
Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe. Set the variable
desired_n
to be
32
. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano. Use the following command to run convert_dice_rolls_to_hex_bytes_2.py and store its output in a text file named "random.txt".
python convert_dice_rolls_to_hex_bytes_2.py > random.txt
The following command will use the Nano editor to open the file random.txt:
nano random.txt
Read the output to see if enough entropy has been produced. If not, go back and generate more dice roll results. If there is enough entropy, delete everything that isn't the entropy value. The Cut Text command deletes an entire line. Backspace and ^D delete one character at a time. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to check the byte length of random.txt:
cat random.txt | tr -d '\n' | wc -c
The result should be 64 (64 hex characters == 32 bytes).
The
tr -d '\n'
command removes newline characters from the data (there is one at the end). The
wc -c
command counts the number of characters in the data. Use the following command to view the entropy value:
cat random.txt
Example random entropy value (64 hex characters, 32 bytes):
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
24) Choose fee rate for a new Bitcoin transaction.
Look at current Bitcoin network transaction fee rates. How to do this is not specified in this recipe. Choose a fee rate (in satoshi / byte) for a new transaction to be made from the storage address. This fee rate should be less than or equal to the relatively high fee rate chosen earlier.
25) If the destination address is standard, perform this step to create the test Bitcoin transaction.
If the destination address is standard, use the following recipe to transfer the available bitcoin from the storage address to the destination address:
Recipe for creating and signing a standard Bitcoin transaction
Open the file create_transaction.py in the Nano editor using this command:
nano create_transaction.py
Use the Nano editor to edit the controls in create_transaction.py, according to the recipe.
- Manually enter the gathered / chosen values (reading them from the online computer's screen), except for the variables
random_value
and
input_data["private_key_hex"]
. - Delete the existing value for the variable
random_value
. Use the Read File command to paste the contents of the file random.txt into the position of the value for this variable (i.e. between the quotation marks). When asked for the "File to insert from", type "random.txt" and press Enter. Press Backspace to delete the final newline byte. - The variable
input_data
is a dictionary that contains several other variables. Delete the existing value for the variable
input_data["private_key_hex"]
. Use the Read File command to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). When asked for the "File to insert from", type "private_key.txt" and press Enter. Press Backspace to delete the final newline byte. - Note: With input values that are rather long, e.g. the txid and the destination address, you can make a copy on the online computer and add spaces to split it into groups of 4 characters. Then you can manually copy each group over to the offline Raspberry Pi (writing them into the open Nano editor), double-check all the groups, and finally delete the spaces again to form the original txid.
Example input values for create_transaction.py:
- random_value:
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
- random_value_type: "hex_bytes"
- input_data["txid"]:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
- input_data["previous_output_index"]: 15
- input_data["private_key_hex"]:
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- input_data["satoshi_amount"]: 200000
- output_data["address"]:
1AGygbyEFYduWkkmZbbvirgS9kuBBMLJCP
- output_data["bitcoin_amount"]: "0.0020"
- change_address:
1AGygbyEFYduWkkmZbbvirgS9kuBBMLJCP
- fee_rate: "66"
- fee_type: "fee_rate"
Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to run create_transaction.py and store its output in a text file named "signed_transaction.txt".
python create_transaction.py > signed_transaction.txt
This may take a few seconds to finish running.
The following command will use the Nano editor to open the file signed_transaction.txt:
nano signed_transaction.txt
The final signed form of the transaction will be displayed at the end of the output. It will look like a single long line of hex characters and it will have the label "Signed transaction:" on the line above it. Use the Next Page command to move down to the end of the file. If the final signed transaction is not present, an error has occurred. Read the output carefully to see if any detail is reported about the error.
Example signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022047367d93de1ebbcd0b4f0bc20c96821a94de5430638b3982799adf4d9f7114760141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01c2d30200000000001976a91465beb01aab71c9da76f38a383c65e3693dff54cc88ac0000000001000000
Delete everything that isn't the final signed form of the transaction. The Cut Text command deletes an entire line. Backspace and ^D delete one character at a time. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to view the signed transaction:
cat signed_transaction.txt
26) Else, if the destination address is nonstandard, perform this step to create the test Bitcoin transaction.
Else, if the destination address is nonstandard, use the following recipe to transfer the available bitcoin from the storage address to the destination address:
Recipe for creating and signing a nonstandard Bitcoin transaction
Open the file create_nonstandard_transaction.py in the Nano editor using this command:
nano create_nonstandard_transaction.py
Use the Nano editor to edit the controls in create_transaction.py, according to the recipe.
- Manually enter the gathered / chosen values (reading them from the online computer's screen), except for the variables
random_value
and
input_data["private_key_hex"]
. - Delete the existing value for the variable
random_value
. Use the Read File command to paste the contents of the file random.txt into the position of the value for this variable (i.e. between the quotation marks). When asked for the "File to insert from", type "random.txt" and press Enter. Press Backspace to delete the final newline byte. - The variable
input_data
is a dictionary that contains several other variables. Delete the existing value for the variable
input_data["private_key_hex"]
. Use the Read File command to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). When asked for the "File to insert from", type "private_key.txt" and press Enter. Press Backspace to delete the final newline byte. - Note: With input values that are rather long, e.g. the txid and the destination address, you can make a copy on the online computer and add spaces to split it into groups of 4 characters. Then you can manually copy each group over to the offline Raspberry Pi (writing them into the open Nano editor), double-check all the groups, and finally delete the spaces again to form the original txid.
Example input values for create_transaction.py:
- random_value:
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
- random_value_type: "hex_bytes"
- input_data["txid"]:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
- input_data["previous_output_index"]: 15
- input_data["private_key_hex"]:
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- input_data["satoshi_amount"]: 200000
- input_data["input_type"]: "p2pkh"
- output_data["address"]:
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- output_data["bitcoin_amount"]: "0.0020"
- output_data["output_type"]: "p2sh"
- change_address:
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- fee_rate: "66"
- fee_type: "fee_rate"
Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to run create_nonstandard_transaction.py and store its output in a text file named "signed_transaction.txt".
python create_nonstandard_transaction.py > signed_transaction.txt
This may take a few seconds to finish running.
The following command will use the Nano editor to open the file signed_transaction.txt:
nano signed_transaction.txt
The final signed form of the transaction will be displayed at the end of the output. It will look like a single long line of hex characters and it will have the label "Signed transaction:" on the line above it. Use the Next Page command to move down to the end of the file. If the final signed transaction is not present, an error has occurred. Read the output carefully to see if any detail is reported about the error.
Example signed nonstandard transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f002203e7ee9b0529ee2c624e71735bfceb08e66c166281984f07e0cfde34c026c7b500141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
Delete everything that isn't the final signed form of the transaction. The Cut Text command deletes an entire line. Backspace and ^D delete one character at a time. Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to view the signed nonstandard transaction:
cat signed_transaction.txt
27) Copy the signed transaction to the online computer.
Manually copy the transaction (in hex byte form) to the online computer.
Use the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online computer.
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
hex_bytes
. Use the Read File command to paste the contents of the file signed_transaction.txt into the position of the value for this variable (i.e. between the quotation marks). When asked for the "File to insert from", type "signed_transaction.txt" and press Enter. Press Backspace to delete the final newline byte. - Use the WriteOut command to save the changes to the file and the Exit command to quit Nano.
Use the following command to run generate_bitcoin_address_3.py and store its output in a text file named "tx_readable.txt".
python display_hex_bytes.py > tx_readable.txt
The following command will use the Nano editor to open the file tx_readable.txt:
nano tx_readable.txt
Follow the rest of the linked subrecipe to manually copy over the signed transaction into a new file named "tx_copied.txt" on the online computer and remove the whitespace.
28) Broadcast and manage the transaction.
Use the following recipe to manage the transaction (i.e. broadcast the transaction, check its confirmation status, and create a new version with a higher fee if the first version is not mined within a reasonable time period):
Recipe for managing the fee and broadcast of a Bitcoin transaction
29) When the test transaction is successfully mined, this shows that the storage address is valid.
When the test transaction (or a new version of it) is successfully mined, the address is now known to be correctly derived from the private key. You can now move a large amount of bitcoin into this address and be certain that you can retrieve it. Even if you later construct a new transaction that turns out to be invalid, and discover that the cause was an error in the code stack used to create and sign a transaction, you know that eventually this error can be fixed and a valid transaction can be created. You risk only a temporary lack of access to the bitcoin stored in this address, not its permanent loss.
30) Transfer larger amount of bitcoin into storage address for long-term storage.
Transfer a relatively larger amount of bitcoin to the storage address for long-term storage. How to do this is not specified in this recipe.
31) Store private key on paper.
You should now store the private key on paper. It is advisable to store multiple copies of the private keys, in case any one copy is lost, damaged, or destroyed.
I recommend:
- Writing down the private key on high-quality paper.
- Storing two copies of the private key together in a sealed waterproof container. Two copies are protection against any damage to one copy. A sealed waterproof container protects the private keys against flood, rain, and damp.
- Storing an additional two copies in a second sealed waterproof container and storing this container in a second separate location. This is protection against the risk of fire in the first location.
To make the private key easier to read, both on the Raspberry Pi and on paper, I recommend adding whitespace in order to break it into groups of 4 characters and lines of 4 groups.
Example: The private key
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
can be written as:
c592 e1da d5e9 871f
deff b551 b454 4b0a
1cf0 378c 6371 d7a3
97ff 5faf 04c9 34ca
deff b551 b454 4b0a
1cf0 378c 6371 d7a3
97ff 5faf 04c9 34ca
It is preferable not to edit the original private_key.txt file, in case you accidentally alter it irreversibly.
Instead, you can:
- Make a copy of the private key file:
cp private_key.txt private_key_tmp.txt
- Open the file private_key_tmp.txt in the Nano editor:
nano private_key_tmp.txt
- In the editor, add a space after every four characters and a newline (by pressing Enter) after every four groups.
- Write down the private key on paper, in the whitespaced format displayed in private_key_tmp.txt. Write carefully in order to avoid ambiguity. Double-check each group against the original group displayed on the offline Raspberry Pi.
- On the Raspberry Pi, use the Exit command to quit the Nano editor. Press 'N' to not save the modified data.
- Delete the temporary copy of the private key file:
rm private_key_tmp.txt
32) List items in work directory on the Raspberry Pi.
At this point, if you use the
ls -1
command to list the items in the work directory, one line per item, you should see a result like this:
pi@raspberrypi ~/work $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random.txt
signed_transaction.txt
storage_address.txt
transaction.py
transaction.pyc
tx_readable.txt
34) Delete private key on Raspberry Pi.
You should store the Raspberry Pi securely, but still delete the private key from it.
Use the following command to delete the file private_key.txt:
rm private_key.txt
33) Shut down Raspberry Pi.
When you have finished using the Raspberry Pi, shut it down.
Use the following command to shut down the Raspberry Pi:
sudo halt
When it has completely shut down, unplug the power cable.
35) Consider preparing and storing a duplicate Raspberry Pi.
You should consider preparing and storing a duplicate offline Raspberry Pi in case the first one is lost, damaged, or destroyed.