edgecase
Threat Level: Apricot
Author: StJohn Piano
Published: 2018-11-16
Datafeed Article 70
This article has been digitally signed by Edgecase Datafeed.
2585 words - 754 lines - 19 pages





Parts


- Description
- Assets
- Notes
- Recipe
- Example




Description


This recipe describes a method of creating and signing a standard Bitcoin transaction with one input and one output.

This transaction will authorise the transfer of an "unspent output" stored at one address to a second address, minus a transaction fee. This unspent output contains a particular value of bitcoin and must be transferred completely in the transaction.




Assets


Asset: A library of functions for handling standard Bitcoin data types.
bitcoin_functions.py [paywalled]

Asset: An implementation of RIPEMD-160, written by Björn Edström.
bjorn_edstrom_ripemd160.py [paywalled]

Asset: A script that creates and signs a standard Bitcoin transaction with one input and one output.
create_transaction.py [paywalled]

Asset: A Python implementation of ECDSA cryptography, written by Peter Pearson.
ecdsa-0.10.tar.gz [paywalled]

Asset: A Python implementation of SHA256.
pypy_sha256.py [paywalled]

Asset: A library of classes for standard Bitcoin transactions.
transaction.py [paywalled]




Notes


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 standard address:
- An uncompressed single-signature Pay-To-Public-Key-Hash (P2PKH) address.

Standard addresses start with the character '1'.

The code used in this recipe only supports transactions with one standard input and one standard output. A standard input spends bitcoin from a standard address. A standard output sends bitcoin to a standard address.

This recipe assumes that you already have a Bitcoin address and have transferred some bitcoin to it. If not, the following article describes how to generate a Bitcoin address:
Recipe for generating a Bitcoin address

This recipe was originally published in the article Creating and signing a standard raw Bitcoin transaction: Iteration #2, in the section Recipes For Using Various Downloadable Assets, in the part "Recipe 3: create_transaction.py". The recipe shown here has been edited for republication.

Several points concerning Bitcoin transactions:
- New transactions spend unspent-outputs-of-previous-transactions.
- 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 unspent outputs. Any change can be sent in a new unspent output back to the original address or another that you control. Unspent outputs cannot be broken into smaller unspent outputs prior to spending - new unspent outputs (larger or smaller) must be created by a new transaction.




Recipe


Definitions:
- input address: the address that currently contains the bitcoin that you want to transfer in this transaction.
- output address: the address to which the bitcoin will be transferred by this transaction.
- previous_output_hash: big-endian 32-byte double-SHA256 hash of a previous transaction.
- txid: "transaction id", the little-endian form of the previous_output_hash.


Initial conditions:
- You must have Python 2.7.x installed on your computer. These code assets 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.
- You must already have a Bitcoin address and the corresponding Bitcoin private key (ideally 32 bytes long). A 32-byte private key will be 64 hex characters long. When used as a control value in this recipe, it must be a 64-character string that consists only of hex characters (the ten digit characters "0123456789" and the lower-case alphabetical characters "abcdef").
- You will need 32 bytes of entropy (per input, but in this recipe there is only 1 input). The following article describes one way to generate this entropy: Recipe for generating entropy bytes using dice. Every ECDSA signature you ever make should use a different random value. Ideally this random value should be 32 bytes long. 1 byte is represented by 2 hex characters, so a 32-byte random value will be 64 hex characters long. When used in this recipe, the random value must be a 64-character string that consists only of hex characters (the ten digit characters "0123456789" and the lower-case alphabetical characters "abcdef").


1) Gather the following pieces of information:

- The txid of the previous transaction that transferred the unspent output to the input address.

- The index of this unspent output in the previous transaction (the "previous_output_index"). This index is implicit and starts at zero, and can be found by examining the list of outputs in the previous transaction, and looking for the particular unspent output that you wish to transfer.

- The private key (in hex bytes) of the input address.

- The bitcoin amount (or satoshi amount) contained within the unspent output. Let's call this the "input amount".

- A 32-byte random value (1 per input), as listed in the initial conditions. The transaction will be signed once using each input and each signature requires 32 bytes of entropy.


2) Choose the following pieces of information:

- The output address.

- The bitcoin amount (or satoshi amount) that you wish to transfer to the output address. Let's call this the "output amount".

Note: This should be equal to the input amount (the code does not have the ability to send change).

- The change address. Any value not assigned to an output address will be assigned to the change address. The fee will be subtracted from the final value assigned to the change address.

Note: This must be the same as the output address. Since, in this recipe, the change address is the same as the only output address, the fee will always be subtracted from the value assigned to the single output address.

- The fee (in satoshi) or fee_rate (in satoshi / byte). The fee must be an integer e.g.
"225"
. The fee_rate must be an integer e.g.
"1"
or a float e.g.
"1.2"
.

Note: You should look up the range of fee rates for transactions that are currently being mined.


3) Create a work directory.


4) Browse to the Assets part of this article and download all the linked assets. List of assets:
- bitcoin_functions.py
- bjorn_edstrom_ripemd160.py
- create_transaction.py
- ecdsa-0.10.tar.gz
- pypy_sha256.py
- transaction.py


5) Move these assets into the work directory.


6) Unpack the zipped tape archive file ecdsa-0.10.tar.gz. This can be done by opening a terminal, changing directory to the work directory, and running the following command:
tar -zxvf ecdsa-0.10.tar.gz

This unpacking should produce a new directory named "ecdsa-0.10" in the work directory. The directory "ecdsa-0.10" should contain a directory named "ecdsa". Copy the "ecdsa" directory into the work directory.


7) Open the file create_transaction.py in a text editor. Scroll to lines 44-68, which should be the section of text that lies between
##### START CONTROLS

and
##### END CONTROLS


Note: In create_transaction.py, all control values are strings (i.e. are contained within quotation marks).


8) Set the variable
random_value
to the 32-byte random value.


9) Set the variable
random_value_type
to
"hex_bytes"
.


10) The variable
input_data
is a dictionary that contains several other variables.

- Set the value of the variable
input_data["txid"]
to be the txid.

- Set the value of the variable
input_data["previous_output_index"]
to be the index of the unspent output.

- Set the value of the variable
input_data["private_key_hex"]
to be the private key.

- If the input amount is in satoshi, set the value of the variable
input_data["satoshi_amount"]
to be the input amount.

- If the input amount is in bitcoin, set the value of the variable
input_data["bitcoin_amount"]
to be the input amount.

Note: Currently, if both of the variables
input_data["satoshi_amount"]
and
input_data["bitcoin_amount"]
are set, then
input_data["bitcoin_amount"]
will take precedence. You can comment out the unused variable of the pair by placing a number sign ('#') at the start of the relevant line.


11) The variable
output_data
is a dictionary that contains several other variables.

- Set the value of the variable
output_data["address"]
to be the output address.

- If the output amount is in satoshi, set the value of the variable
output_data["satoshi_amount"]
to be the output amount.

- If the output amount is in bitcoin, set the value of the variable
output_data["bitcoin_amount"]
to be the output amount.

Note: Currently, if both of the variables
output_data["satoshi_amount"]
and
output_data["bitcoin_amount"]
are set,
output_data["bitcoin_amount"]
will take precedence. You can comment out the unused variable of the pair by placing a number sign ('#') at the start of the relevant line.


12) Set the variable
change_address
to be the change address.


13) If you have chosen to set the fee as an absolute number of satoshi, set the variable
fee
to be the fee amount and set the variable
fee_type
to be
"fee"
.


14) If you have chosen to set the fee as a fee rate (in satoshi / byte), set the variable
fee_rate
to be the fee rate and set the variable
fee_type
to be
"fee_rate"
.


15) Open a terminal and change directory to the work directory.


16) Run the following command:
python create_transaction.py


At the end, the output should contain the signed transaction as a hex byte sequence without spaces.




Example


I'm going to attempt to replicate tx1 from the article Creating and signing a standard raw Bitcoin transaction: Iteration #2.


In the linked article, I can see the information gathered / chosen in order to create tx1:

Source address:
- Private key (raw bytes):
"the_mote_in_god's_eye"
- Private key (hex bytes):
7468655f6d6f74655f696e5f676f6427735f657965
- Bitcoin address:
138obEZkdWaWEQ4x8ZAYw4MybHSZtX1Nam
- Current balance: 0.00242 BTC

Target address:
- Private key (raw bytes):
"roadside_picnic"
- Bitcoin address:
13xPBB175FtPbPQ84iB8KuawaVy3mHrady

Previous transaction containing the unspent output that I wish to spend:
- txid:
e4609e0f1ca854b8b07381f32ba31adbad9713205f5a4f3f56a5a32853d47855
- previous_output_hash:
5578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4
- previous_output_index: 8
- scriptPubKey of relevant unspent output from previous transaction:
76a914176a0e0c2b9b0e77d630712ad301b749102a304488ac

Value of unspent output:
- 0.00242 btc

Value to send to output address:
- 0.002 btc

- Random value (raw bytes):
"The Face of God dhcmrlchtdj"

fee_rate = 1 (satoshi / byte)


I'll convert the random value to hex bytes.
- Random value (hex bytes):
5468652046616365206f6620476f64206468636d726c636874646a


Note: "Value to send to output address" is set to be less than the unspent output value in order to demonstrate that any unassigned value will be sent to the change address.


Note: During the project shown in the linked article, I used raw byte private keys for convenience. The input address's private key was converted to hex byte form so that it could be used as a control value. It is only 21 bytes long. For serious use, the private key should be 32 bytes long and generated from a high-quality entropy source. This note also applies to the random value (which is only 27 bytes long here).


Let's put these gathered / chosen values into the order described within the recipe:

Gathered:

- txid:
e4609e0f1ca854b8b07381f32ba31adbad9713205f5a4f3f56a5a32853d47855

- previous_output_index:
8

- private key (hex bytes):
7468655f6d6f74655f696e5f676f6427735f657965

- input amount (bitcoin):
0.00242

- 32-byte random value (only 27 bytes long in this case):
5468652046616365206f6620476f64206468636d726c636874646a


Chosen:

- output address:
13xPBB175FtPbPQ84iB8KuawaVy3mHrady

- output amount (bitcoin):
0.002

- change address:
13xPBB175FtPbPQ84iB8KuawaVy3mHrady

- fee_rate (satoshi / byte):
1




Follow the recipe.

Open the file create_transaction.py in a text editor. Scroll to lines 44-68, which is the section of text that lies between
##### START CONTROLS

and
##### END CONTROLS


As shown in the recipe, set the relevant variables to contain the gathered / chosen control values.

Results:

create_transaction.py

python 2.7.13
	##### START CONTROLS
	# Note: Hex characters in input variable values must be lowercase. 
	random_value = "5468652046616365206f6620476f64206468636d726c636874646a"
	# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters (1 byte is represented by 2 hex characters). 
	# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy. 
	# random_value_type options: ["raw_bytes", "hex_bytes"]
	random_value_type = "hex_bytes"
	input_data = {
		"txid": "e4609e0f1ca854b8b07381f32ba31adbad9713205f5a4f3f56a5a32853d47855",
		"previous_output_index": "8",
		"private_key_hex": "7468655f6d6f74655f696e5f676f6427735f657965",
		#"satoshi_amount": "242000", 
		"bitcoin_amount": "0.00242", 
		}
	output_data = {
		"address": "13xPBB175FtPbPQ84iB8KuawaVy3mHrady",
		#"satoshi_amount": "200000", 
		"bitcoin_amount": "0.002", 
		}
	# note: all inputs and outputs are assumed to be Pay-To-Public-Key-Hash (P2PKH). 
	change_address = "13xPBB175FtPbPQ84iB8KuawaVy3mHrady" 
	# note: the fee will be subtracted from the amount that is being sent to the change address.
	fee = "223" # satoshi
	fee_rate = "1" # satoshi / byte
	# fee_type options: ["fee", "fee_rate"]
	fee_type = "fee_rate"
	##### END CONTROLS




Now run the script. This is a demonstration of creating a signed transaction that authorises a specified transfer of bitcoin.


aineko:work stjohnpiano$ python create_transaction.py


### START CREATION OF BITCOIN TRANSACTION

- Fee type: fee_rate
- Fee rate: 1.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 13xPBB175FtPbPQ84iB8KuawaVy3mHrady
- Amount to be sent to the change address: 0.002
- Input addresses, with total-value-to-be-sent:
-- 138obEZkdWaWEQ4x8ZAYw4MybHSZtX1Nam: 0.00242000
- Output addresses, with total-value-to-be-received:
-- 13xPBB175FtPbPQ84iB8KuawaVy3mHrady: 0.00200000
- Total value of all inputs: 0.00242000
- Total value of all outputs: 0.00200000
- Total value of all inputs is greater than total value of all outputs.
-- Some input value has not been assigned to an output.
-- Extra value: 0.00042000
-- This extra value will be sent to the change address.
-- Change address: 13xPBB175FtPbPQ84iB8KuawaVy3mHrady
-- New amount to be sent to change address: 0.00242000
- Estimated transaction size: 223 bytes
- Fee rate: 1.0 (satoshi / byte)
- Calculate 223 * 1.0 and round up to nearest satoshi.
- Final fee: 223 (satoshi)
- Final fee rate (using estimated transaction size): 1.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 241777 (satoshi)

Input 0:
Input (without signature):
- previous_output_hash: 5578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4
- previous_output_index: 08000000
- sequence: ffffffff
- private_key_hex: 00000000000000000000007468655f6d6f74655f696e5f676f6427735f657965
- public_key_hex: 041ad06846fd7cf9998a827485d8dd5aaba9eccc385ba7759a6e9055fbdf90d7513c0d11fe5e5dcfcf8d4946c67f6c45f8e7f7d7a9c254ca8ebde1ffd64ab9dd58
- script_length_scriptPubKey: 19
- scriptPubKey: 76a914176a0e0c2b9b0e77d630712ad301b749102a304488ac
- script_length: None
- scriptSig: None
- address: 138obEZkdWaWEQ4x8ZAYw4MybHSZtX1Nam
- previous_output_index_int: 8
- txid: e4609e0f1ca854b8b07381f32ba31adbad9713205f5a4f3f56a5a32853d47855

Output 0:
Output:
- value: 71b0030000000000
- script_length: 19
- scriptPubKey: 76a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac
- address: 13xPBB175FtPbPQ84iB8KuawaVy3mHrady
- bitcoin_amount: 0.00241777
- satoshi_amount: 241777
- public_key_hash_hex: 2069a3fae01db74cef12d1d01811afdf6a3e1c2e

Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: 5578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4
-- previous_output_index: 08000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output:
-- value: 71b0030000000000
-- script_length: 19
-- scriptPubKey: 76a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac
- block_lock_time: 00000000

Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: 5578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4
-- previous_output_index: 08000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a914176a0e0c2b9b0e77d630712ad301b749102a304488ac
-- sequence: ffffffff
- output_count: 01
- Output:
-- value: 71b0030000000000
-- script_length: 19
-- scriptPubKey: 76a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac
- block_lock_time: 00000000
- hash_type_4_byte: 01000000

Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: 5578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4
-- previous_output_index: 08000000
-- script_length: 8a
-- scriptSig: 473044022017ece35581a034a4838a577fe438f108cf22764927a1ad197ed379460c0764cd022066723723eff05c10bac9a2f63b3e782e24fde290701c9408f3d1054722adad360141041ad06846fd7cf9998a827485d8dd5aaba9eccc385ba7759a6e9055fbdf90d7513c0d11fe5e5dcfcf8d4946c67f6c45f8e7f7d7a9c254ca8ebde1ffd64ab9dd58
-- sequence: ffffffff
- output_count: 01
- Output:
-- value: 71b0030000000000
-- script_length: 19
-- scriptPubKey: 76a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac
- block_lock_time: 00000000
- hash_type_4_byte: 01000000

Signed transaction:
01000000015578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4080000008a473044022017ece35581a034a4838a577fe438f108cf22764927a1ad197ed379460c0764cd022066723723eff05c10bac9a2f63b3e782e24fde290701c9408f3d1054722adad360141041ad06846fd7cf9998a827485d8dd5aaba9eccc385ba7759a6e9055fbdf90d7513c0d11fe5e5dcfcf8d4946c67f6c45f8e7f7d7a9c254ca8ebde1ffd64ab9dd58ffffffff0171b00300000000001976a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac0000000001000000

### END CREATION OF BITCOIN TRANSACTION




The final signed transaction is:

01000000015578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4080000008a473044022017ece35581a034a4838a577fe438f108cf22764927a1ad197ed379460c0764cd022066723723eff05c10bac9a2f63b3e782e24fde290701c9408f3d1054722adad360141041ad06846fd7cf9998a827485d8dd5aaba9eccc385ba7759a6e9055fbdf90d7513c0d11fe5e5dcfcf8d4946c67f6c45f8e7f7d7a9c254ca8ebde1ffd64ab9dd58ffffffff0171b00300000000001976a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac0000000001000000




I'll confirm that this is identical to the original signed tx1 that was broadcast in the previous project.


[original tx1]
aineko:work stjohnpiano$ s1="01000000015578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4080000008a473044022017ece35581a034a4838a577fe438f108cf22764927a1ad197ed379460c0764cd022066723723eff05c10bac9a2f63b3e782e24fde290701c9408f3d1054722adad360141041ad06846fd7cf9998a827485d8dd5aaba9eccc385ba7759a6e9055fbdf90d7513c0d11fe5e5dcfcf8d4946c67f6c45f8e7f7d7a9c254ca8ebde1ffd64ab9dd58ffffffff0171b00300000000001976a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac0000000001000000"


[newly-calculated tx1]
aineko:work stjohnpiano$ s2="01000000015578d45328a3a5563f4f5a5f201397addb1aa32bf38173b0b854a81c0f9e60e4080000008a473044022017ece35581a034a4838a577fe438f108cf22764927a1ad197ed379460c0764cd022066723723eff05c10bac9a2f63b3e782e24fde290701c9408f3d1054722adad360141041ad06846fd7cf9998a827485d8dd5aaba9eccc385ba7759a6e9055fbdf90d7513c0d11fe5e5dcfcf8d4946c67f6c45f8e7f7d7a9c254ca8ebde1ffd64ab9dd58ffffffff0171b00300000000001976a9142069a3fae01db74cef12d1d01811afdf6a3e1c2e88ac0000000001000000"


aineko:work stjohnpiano$ [[ "$s1" = "$s2" ]] && echo equal || echo not-equal

equal



Excellent. They're identical. I've followed the recipe, using the same inputs, and have re-created the signed transaction from the previous project.