pybitcash/bitcash

Unsupported hash type ripemd160

Closed this issue · 9 comments

Tested on OpenSSL 3.0.2, Python 3.10, Linux Ubuntu 22.04 LTS.

Hashlib raises ValueError: unsupported hash type ripemd160, in ripemd160_sha256 function in crypto.py. Found the reason for the issue here.

Hashlib uses OpenSSL for ripemd160 and apparently OpenSSL disabled some older crypto algos around version 3.0 in November 2021. All the functions are still there but require manual enabling. See issue 16994 of OpenSSL github project for details.

The stackoverflow answer details how to enable legacy crypto algorithms, but I think a default solution is needed to use ripemd160.

How does this impact BitCash?

BitCash uses the hash160 (ripemd160_sha256) function to convert public keys to cashaddress and public key hashes for output locking script of P2PKH outputs. This affects the primary functionality of BitCash as a P2PKH wallet.

hash160 uses the hashlib of python, which uses the OpenSSL implementation of ripemd160 which no longer works by default (as tested on OpenSSL 3.0.2, Python 3.10, Linux Ubuntu 22.04 LTS).

I am unable to reproduce this.

Can you send a minimal reproducible example?

from hashlib import new, sha256
new("ripemd160", sha256(b"a").digest()).digest()

I tested this on OpenSSL 3.0.2, Python 3.10.6.
Apparently OpenSSL had already marked ripemd160 as legacy algorithm. Do check if you have already enabled legacy_sect as noted here, if you are on the same version of OpenSSL.

This is what my default openssl.cnf file looked like. (only showing relevant options)

openssl_conf = openssl_init

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect

[default_sect]
# activate = 1

This led the above python code to give "ValueError: unsupported hash type ripemd160"

After when I enabled legacy algorithms, as given here, the ripemd160 code gave no errors.

from hashlib import new, sha256
new("ripemd160", sha256(b"a").digest()).digest()

This works on my environment (macOS, Python 3.10.6, LibreSSL 3.3.6).

In [1]: from hashlib import new, sha256
   ...: new("ripemd160", sha256(b"a").digest()).digest()
Out[1]: b'\x99CU\x19\x9eQo\xf7lO\xa4\xaa\xb3\x937\xb9\xd8L\xf1+'

I can try to reproduce in a different environment.

What would be a way to solve this within BitCash? And how much work would that involve?

It seems its a OpenSSl only problem. Other bitcoin libraries have dealt with the same: bitcoin/bitcoin#23710.

Most straightforward way would be to code python native ripemd160 code, as done here

Seems pretty straightforward:

def ripemd160(data):
    """Compute the RIPEMD-160 hash of data."""
    # Initialize state.
    state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0)
    # Process full 64-byte blocks in the input.
    for b in range(len(data) >> 6):
        state = compress(*state, data[64*b:64*(b+1)])
    # Construct final blocks (with padding and size).
    pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63)
    fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little')
    # Process final blocks.
    for b in range(len(fin) >> 6):
        state = compress(*state, fin[64*b:64*(b+1)])
    # Produce output.
    return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state)

Would you be willing to submit a PR for that?

I am able to reproduce. Looking forward to merging this change 👍🏻