edgecase
For although light oftenest behaves as a wave, it can be looked on as a mote, the lightbit. We have already said by the way that a mote of stuff can behave not only as a chunk, but as a wave. Down among the unclefts, things do not happen in steady flowings, but in leaps between bestandings that are forbidden. The knowledge-hunt of this is called lump beholding.
Author: StJohn Piano
Published: 2018-11-17
Datafeed Article 73
This article has been digitally signed by Edgecase Datafeed.
This article has been digitally signed by its author.
1685 words - 581 lines - 15 pages





GOAL



Display hex bytes in a form that allows a user to easily read them on the screen of one computer and type them into another computer.




CONTENTS



- Goal
- Contents
- Summary
- Downloadable Assets
- Recipe For Manually Copying A Bitcoin Transaction Generated Offline To An Online Computer
- Examples
- Further Work
- Project Log




SUMMARY



I developed a script that prints a hex byte string, inserting spaces and newlines to make it more readable.

For details about how to use this script, please see the section Recipe For Manually Copying A Bitcoin Transaction Generated Offline To An Online Computer.




DOWNLOADABLE ASSETS



Asset: A script that prints a hex byte string, inserting spaces and newlines to make it more readable.
display_hex_bytes.py [paywalled]




RECIPE FOR MANUALLY COPYING A BITCOIN TRANSACTION GENERATED OFFLINE TO AN ONLINE COMPUTER



Initial conditions:
- You must have Python 2.7.x installed on your offline computer. The code asset was developed and 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.

1) Obtain the script display_hex_bytes.py from the Downloadable Assets section of this article.

2) Copy display_hex_bytes.py onto the offline computer. How to do this is not specified in this recipe.

3) Generate the Bitcoin transaction offline. How to do this is not specified in this recipe.

4) Open the script display_hex_bytes.py in a text editor. Scroll to lines 12-15, which should be the section of text that lies between
##### START CONTROLS

and
##### END CONTROLS


5) Set the variable
hex_bytes
to be the hex byte string form of the signed transaction. This string must consist only of hex characters (the ten digit characters "0123456789" and the lower-case alphabetical characters "abcdef").

6) Set the variable
group_size
to be your desired number of characters per group. Groups are divided by spacing.

7) Set the variable
groups_per_line
to be your desired number of character groups to be printed on each line.

8) Set the variable
spaces_between_groups
to be your desired number of space characters in the spacing between each group.

9) Open a terminal and change directory to the directory containing display_hex_bytes.py.

10) Run the following command:
python display_hex_bytes.py


11) The transaction should now be displayed on the screen of the offline computer in a readable format. Manually type the transaction into a text file on an online computer. The rest of this recipe will assume that this text file was named "tx_copied.txt".

12) Transform the transaction back into its original form by running the following sequence of bash commands:

- Remove spaces and newlines from the file and store the result in a new file:
cat tx_copied.txt | tr -d ' \n' > tx.txt


- Add an empty line (i.e. a newline) to the end of the file:
echo '' >> tx.txt


- Print the contents of the resulting file:
cat tx.txt



Please see the Examples section of this article to see a sequence of example results produced by this recipe.




EXAMPLES



The original signed transaction:

01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000



Settings in display_hex_bytes.py:

display_hex_bytes.py

python 2.7.13
	### START CONTROLS
	hex_bytes = "01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000"
	group_size = 4 # number of characters in a group
	groups_per_line = 4
	spaces_between_groups = 2
	### END CONTROLS



Running the script:

aineko:work stjohnpiano$ python display_hex_bytes.py

0100 0000 018b c44c
f2d3 f7f3 0b77 4ae6
197d 999b 2f9a 5c15
032b f0f7 7b3b 76f8
4bef 167a bf00 0000
008a 4730 4402 2041
9eca e5ca 010d b8a2
c7ec 04cd ebaa 58a9
21b0 1020 34db 08d6
4560 87c7 9349 4e02
2048 cf34 5bf5 0490
5a23 021b 3dbd 95d7
a53d 8786 6785 05a3
c5cd 72e0 3ea2 59df
2301 4104 9d8a 4c39
47fb 596c 2664 218f
279b e9ba 2c04 21ca
0068 8824 3877 cdb0
c014 6202 a2a2 af29
9928 cc63 4d58 976d
b320 23fa cf26 9c1f
b706 9d9a f25c 54c0
7e85 eb8e ffff ffff
01b0 3301 0000 0000
0017 a914 fdca 5619
9620 26e5 d80a 84d3
e25f 5cea 931c e385
8700 0000 0001 0000
00



[Here, assume that the transaction shown has been manually typed into a file called "tx_copied.txt".]


Transforming the transaction back into its original form by running the specified sequence of bash commands:

[Remove spaces and newlines from the file and store the result in a new file.]
aineko:work stjohnpiano$ cat tx_copied.txt | tr -d ' \n' > tx.txt


[Add an empty line (i.e. a newline) to the end of the file.]
aineko:work stjohnpiano$ echo '' >> tx.txt


[Print the contents of the resulting file.]
aineko:work stjohnpiano$ cat tx.txt

01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000





FURTHER WORK



Add line numbers to the beginning of each line, with a separating character.
Example:
0000: 0100 0000 018b c44c
0001: f2d3 f7f3 0b77 4ae6
0002: 197d 999b 2f9a 5c15



Add a checksum to the end of each line, and a final checksum for the entire transaction in an extra final line. Then, if a human transcriber were to make a transcription error, a script could mechanically locate the line in which the error existed.










PROJECT LOG



My work computer: Aineko, a 2008 Macbook running Mac OS X 10.6.8 Snow Leopard.

aineko:work stjohnpiano$ python --version

Python 2.7.13



During the project Using a transaction to validate a Bitcoin address, I created the following signed Bitcoin transaction:

01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000



If I had created this transaction on an offline computer, I would want to be able to transfer it to an online computer (for broadcasting) without using a memory stick.

One way to do this is to display the signed transaction string on the screen of the offline computer and manually type it into a text file on the online computer.

The whole transaction in one string is a bit hard to copy. It's easy to lose your place in the string as you go.

It would be easier if the transaction were displayed in small strings of a specific size.

So, I'll develop a script that takes a hex byte string as an input, formats it in a specified way, and prints the result to the screen.


[development occurs here]



display_hex_bytes.py

python 2.7.13


### DESCRIPTION
# - This script:
# -- divides a hex byte string into groups of characters. 
# -- prints these groups to the screen, including a particular number of groups on each line. 


def main():

	### START CONTROLS
	hex_bytes = "01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000"
	group_size = 4 # number of characters in a group
	groups_per_line = 4
	spaces_between_groups = 2
	### END CONTROLS
	
	
	### START PROCESSING
	
	validate_hex(hex_bytes)
	
	n = len(hex_bytes) # total number of characters
	spacing = " " * spaces_between_groups
	
	chars_per_line = group_size * groups_per_line
	for i in range(0, n, chars_per_line):
		section = hex_bytes[i:i+chars_per_line]
		m = len(section) # number of characters in a line. 
		# note: the last line may not contain exactly chars_per_line characters. 
		line = ""
		for j in range(0, m, group_size):
			p = i + j # p = position
			group = hex_bytes[p:p+group_size]
			line += "%s%s" % (group, spacing)
		print line
	
	### END PROCESSING




def validate_hex(input):
	validate_string(input)
	if not is_hex(input):
		message = "Input must consist only of hex characters. Input: %s" % input
		stop(message)
	# 2 hex characters represents 1 byte, so input must have an even number of characters.
	if len(input) % 2 == 0:
		return True
	else:
		message = "Input must have an even number of hex characters. Input: %s" % input
		stop(message)
	message = "Unknown problem in function validate_hex()."
	stop(message)


def is_hex(input):
	hex_characters = "0123456789abcdef"
	for c in input: # c = character
		if c not in hex_characters:
			return False
	return True

	
def validate_string(input):
	if isinstance(input, str):
		return True
	message = "Input is not a string. Input type is: %s" % type(input)
	stop(message)
	
	
def stop(message):
	# raise an Exception to get a traceback. 
	raise Exception("\n\nERROR: %s\n" % message)
	

if __name__ == '__main__': main()





Let's run it.


aineko:work stjohnpiano$ python display_hex_bytes.py

0100 0000 018b c44c
f2d3 f7f3 0b77 4ae6
197d 999b 2f9a 5c15
032b f0f7 7b3b 76f8
4bef 167a bf00 0000
008a 4730 4402 2041
9eca e5ca 010d b8a2
c7ec 04cd ebaa 58a9
21b0 1020 34db 08d6
4560 87c7 9349 4e02
2048 cf34 5bf5 0490
5a23 021b 3dbd 95d7
a53d 8786 6785 05a3
c5cd 72e0 3ea2 59df
2301 4104 9d8a 4c39
47fb 596c 2664 218f
279b e9ba 2c04 21ca
0068 8824 3877 cdb0
c014 6202 a2a2 af29
9928 cc63 4d58 976d
b320 23fa cf26 9c1f
b706 9d9a f25c 54c0
7e85 eb8e ffff ffff
01b0 3301 0000 0000
0017 a914 fdca 5619
9620 26e5 d80a 84d3
e25f 5cea 931c e385
8700 0000 0001 0000
00



Excellent.



Now, let's imagine I've generated this transaction on an offline computer, and I've typed it into a text file on an online computer.

I would next wish to remove spaces and newlines, so that the reconstituted hex string would be ready for broadcast.



Copy the result above into a text file.



tx_copied.txt
0100 0000 018b c44c f2d3 f7f3 0b77 4ae6 197d 999b 2f9a 5c15 032b f0f7 7b3b 76f8 4bef 167a bf00 0000 008a 4730 4402 2041 9eca e5ca 010d b8a2 c7ec 04cd ebaa 58a9 21b0 1020 34db 08d6 4560 87c7 9349 4e02 2048 cf34 5bf5 0490 5a23 021b 3dbd 95d7 a53d 8786 6785 05a3 c5cd 72e0 3ea2 59df 2301 4104 9d8a 4c39 47fb 596c 2664 218f 279b e9ba 2c04 21ca 0068 8824 3877 cdb0 c014 6202 a2a2 af29 9928 cc63 4d58 976d b320 23fa cf26 9c1f b706 9d9a f25c 54c0 7e85 eb8e ffff ffff 01b0 3301 0000 0000 0017 a914 fdca 5619 9620 26e5 d80a 84d3 e25f 5cea 931c e385 8700 0000 0001 0000 00




Remove spaces and newlines from the file and store the result in a new file.

aineko:work stjohnpiano$ cat tx_copied.txt | tr -d ' \n' > tx.txt


[add an empty line (i.e. a newline) to the end of the file]
aineko:work stjohnpiano$ echo -e '' >> tx.txt


aineko:work stjohnpiano$ cat tx.txt

01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000



Reconstituted transaction:

01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000





So, the transaction could now be broadcast.


Let's double-check the process by confirming that the transaction hasn't been changed during its division and reconstitution.


[original tx]
aineko:work stjohnpiano$ s1="01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000"


[tx produced by the process in this project]
aineko:work stjohnpiano$ s2="01000000018bc44cf2d3f7f30b774ae6197d999b2f9a5c15032bf0f77b3b76f84bef167abf000000008a4730440220419ecae5ca010db8a2c7ec04cdebaa58a921b0102034db08d6456087c793494e022048cf345bf504905a23021b3dbd95d7a53d8786678505a3c5cd72e03ea259df230141049d8a4c3947fb596c2664218f279be9ba2c0421ca006888243877cdb0c0146202a2a2af299928cc634d58976db32023facf269c1fb7069d9af25c54c07e85eb8effffffff01b03301000000000017a914fdca5619962026e5d80a84d3e25f5cea931ce385870000000001000000"


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

equal



Excellent. The transaction was not changed by the process.