#!/usr/bin/env python3
from bip_utils import Bip84, Bip84Coins, Bip44Changes
from mnemonic import Mnemonic
import hmac, hashlib
from ecdsa import SECP256k1, SigningKey

mn = Mnemonic("english")
mnemonic_str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
seed = mn.to_seed(mnemonic_str)

bip84 = Bip84.FromSeed(seed, Bip84Coins.BITCOIN)
account = bip84.Purpose().Coin().Account(acc_idx=0)
chain = account.Change(Bip44Changes.CHANGE_EXTERNAL)
addr_obj = chain.AddressIndex(0)

priv_key = bytes(addr_obj.PrivateKey().Raw())
print("bip-utils final priv key:", priv_key.hex())

sk = SigningKey.from_string(priv_key, curve=SECP256k1)
vk = sk.verifying_key
pub_uncompressed = vk.to_string()
y = int.from_bytes(pub_uncompressed, "big")
prefix = 0x02 if y % 2 == 0 else 0x03
pub_compressed = bytes([prefix]) + pub_uncompressed[:32]
print("Computed pubkey:", pub_compressed.hex())

def hash160(data):
    h = hashlib.new("ripemd160")
    h.update(hashlib.sha256(data).digest())
    return h.digest()

h160 = hash160(pub_compressed)
print("H160:", h160.hex())

bech32_obj = addr_obj.ToBech32()
addr = bech32_obj.Payload()
print("\nbip-utils address:", addr)

def bech32_encode(hrp, data_bytes):
    charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
    def convertbits(data, frombits, tobits, pad=True):
        acc = 0
        bits = 0
        ret = []
        maxv = (1 << tobits) - 1
        for v in data:
            acc = (acc << frombits) | v
            bits += frombits
            while bits >= tobits:
                bits -= tobits
                ret.append((acc >> bits) & maxv)
        if pad and bits:
            ret.append((acc << (tobits - bits)) & maxv)
        return ret
    def polymod(values):
        GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
        res = 1
        for v in values:
            b = res >> 25
            res = ((res & 0x1ffffff) << 5) ^ v
            for i in range(5):
                res ^= GEN[i] if ((b >> i) & 1) else 0
        return res ^ 1
    data5 = convertbits([0x00] + list(data_bytes), 8, 5)
    payload = [0x00] + data5
    checksum = polymod([0] + [ord(c) for c in hrp] + [0] + payload + [0]*6)
    for i in range(6):
        payload.append((checksum >> (5 * (5 - i))) & 0x1f)
    return hrp + "1" + "".join(charset[d] for d in payload)

my_addr = bech32_encode("bc", h160)
print("My bech32:          ", my_addr)
print()
print("MATCH:", my_addr == addr)