Charles Haughey
Charles Haughey

Reputation: 61

python 3 print result of function giving error

I have researched this question thoroughly here:

and I have tried various layouts to try and get it to work.

print(merkle(txtHashes))
ha = merkle(txtHashes)
print(ha)

the code comes from here a Python 2.7 script see below:

import hashlib

# Hash pairs of items recursively until a single value is obtained
def merkle(hashList):
    if len(hashList) == 1:
        return hashList[0]
    newHashList = []
    # Process pairs. For odd length, the last is skipped
    for i in range(0, len(hashList)-1, 2):
        newHashList.append(hash2(hashList[i], hashList[i+1]))
    if len(hashList) % 2 == 1: # odd, hash last item twice
        newHashList.append(hash2(hashList[-1], hashList[-1]))
    return merkle(newHashList)

def hash2(a, b):
    # Reverse inputs before and after hashing
    # due to big-endian / little-endian nonsense
    a1 = a.decode('hex')[::-1]
    b1 = b.decode('hex')[::-1]
    h = hashlib.sha256(hashlib.sha256(a1+b1).digest()).digest()
    return h[::-1].encode('hex')

txtHashes = [
  "00baf6626abc2df808da36a518c69f09b0d2ed0a79421ccfde4f559d2e42128b",
  "91c5e9f288437262f218c60f986e8bc10fb35ab3b9f6de477ff0eb554da89dea",
  "46685c94b82b84fa05b6a0f36de6ff46475520113d5cb8c6fb060e043a0dbc5c"]

print merkle(txtHashes)

This works on Python 2.7, I can't get it to work on Python 3 even when I change the bottom line to

print(merkle(txtHashes))

Error given:

Traceback (most recent call last):
  File "C:/Python30/MerkleRootTrial.py", line 126, in <module>
    print(merkle(txtHashes))
  File "C:/Python30/MerkleRootTrial.py", line 10, in merkle
    newHashList.append(hash2(hashList[i], hashList[i+1]))
  File "C:/Python30/MerkleRootTrial.py", line 18, in hash2
    a1 = a.decode('hex')[::-1]
AttributeError: 'str' object has no attribute 'decode'

Upvotes: 0

Views: 215

Answers (2)

tfred
tfred

Reputation: 31

To add to benediktwerner's answer, you can also decode the hex string to bytes using the following two methods in python 3.x:

import codecs
a1 = codecs.decode(a, 'hex_codec')[::-1]

Or, if you prefer not to import:

a1 = bytes.fromhex(a)[::-1]

From these two examples, the returned values for a1 are equal.

Upvotes: 1

benediktwerner
benediktwerner

Reputation: 88

In Python 3 str and bytes are different types while they were the same in Python 2. In Python 3 only bytes-objects have a decode() function and only str-objects have encode(), so you can't do a.decode('hex') because a is a str.

Also, some (I think all?) pseudo-encodings like "hex" (and a few others like "zip" and "rot13") were removed, so you can't convert strings and bytes from/to hex anymore using en/decode(). Instead, you can use binascii:

import binascii

binascii.hexlify(a) # instead of a.encode("hex")
binascii.unhexlify(a) # instead of a.decode("hex")

Note, that hexlify() only takes bytes-objects (which only makes sense) and both of those methods also return bytes-objects, but you can convert str to bytes and the other way around using en/decode():

b"abc".decode() -> "abc"
"abc".encode() -> b"abc"

In your case you need to import binascii change hash2 to this:

def hash2(a, b):
    # Reverse inputs before and after hashing
    # due to big-endian / little-endian nonsense
    a1 = binascii.unhexlify(a)[::-1]
    b1 = binascii.unhexlify(b)[::-1]
    h = hashlib.sha256(hashlib.sha256(a1+b1).digest()).digest()
    return binascii.hexlify(h[::-1]) # add .decode() here if you want str instead of bytes

Upvotes: 2

Related Questions