import hashlib, random, string

random.seed(101)

# ---------- Bitcoin legacy (P2PKH) address with valid base58check checksum ----------
B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def base58check_encode(payload_bytes):
    checksum = hashlib.sha256(hashlib.sha256(payload_bytes).digest()).digest()[:4]
    full = payload_bytes + checksum
    n = int.from_bytes(full, 'big')
    encoded = ''
    while n > 0:
        n, r = divmod(n, 58)
        encoded = B58[r] + encoded
    # leading zero bytes -> leading '1's
    n_leading_zeros = len(full) - len(full.lstrip(b'\x00'))
    return '1' * n_leading_zeros + encoded

def gen_btc_legacy():
    version = b'\x00'  # mainnet P2PKH
    pubkey_hash = bytes(random.getrandbits(8) for _ in range(20))
    return base58check_encode(version + pubkey_hash)

def gen_btc_p2sh():
    version = b'\x05'  # mainnet P2SH (starts with 3)
    script_hash = bytes(random.getrandbits(8) for _ in range(20))
    return base58check_encode(version + script_hash)

# ---------- Bech32 (bc1...) ----------
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"

def bech32_polymod(values):
    GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
    chk = 1
    for v in values:
        b = chk >> 25
        chk = (chk & 0x1ffffff) << 5 ^ v
        for i in range(5):
            chk ^= GEN[i] if ((b >> i) & 1) else 0
    return chk

def bech32_hrp_expand(hrp):
    return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]

def bech32_create_checksum(hrp, data):
    values = bech32_hrp_expand(hrp) + data
    polymod = bech32_polymod(values + [0,0,0,0,0,0]) ^ 1
    return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]

def convertbits(data, frombits, tobits, pad=True):
    acc = 0; bits = 0; ret = []
    maxv = (1 << tobits) - 1
    for value in data:
        acc = (acc << frombits) | value
        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 gen_btc_bech32():
    witver = 0
    witprog = bytes(random.getrandbits(8) for _ in range(20))
    data = [witver] + convertbits(list(witprog), 8, 5)
    checksum = bech32_create_checksum('bc', data)
    combined = data + checksum
    return 'bc1' + ''.join(CHARSET[d] for d in combined)

# ---------- Ethereum address (format-valid hex, no EIP-55 mixed case) ----------
def gen_eth_address():
    return '0x' + ''.join(random.choice('0123456789abcdef') for _ in range(40))

print("BTC legacy:", gen_btc_legacy())
print("BTC legacy 2:", gen_btc_legacy())
print("BTC P2SH:", gen_btc_p2sh())
print("BTC bech32:", gen_btc_bech32())
print("ETH addr 1:", gen_eth_address())
print("ETH addr 2:", gen_eth_address())

# ---------- BIP-39-style mnemonic using confirmed real wordlist entries ----------
known_bip39_words = [
"abandon","ability","able","about","above","absent","absorb","abstract","absurd","abuse",
"access","accident","account","accuse","achieve","acid","acoustic","acquire","across","act",
"action","actor","actress","actual","adapt","add","addict","address","adjust","admit",
"adult","advance","advice","aerobic","affair","afford","afraid","again","age","agent",
"agree","ahead","aim","air","airport","aisle","alarm","album","alcohol","alert",
"alien","all","alley","allow","almost","alone","alpha","already","also","alter",
"always","amateur","amazing","among","amount","amused","analyst","anchor","ancient","anger",
"angle","angry","animal","ankle","announce","annual","another","answer","antenna","antique",
"anxiety","any","apart","apology","appear","apple","approve","april","arch","arctic",
"area","arena","argue","arm","armed","armor","army","around","arrange","arrest",
"arrive","arrow","art","artefact","artist","artwork","ask","aspect","assault","asset",
"assist","assume","asthma","athlete","atom","attack","attend","attitude","attract","auction",
"audit","august","aunt","author","auto","autumn","average","avocado","avoid","awake",
]

def gen_mnemonic(n_words=12):
    return ' '.join(random.sample(known_bip39_words, n_words))

random.seed(202)
print("Mnemonic 12:", gen_mnemonic(12))
random.seed(303)
print("Mnemonic 12b:", gen_mnemonic(12))
random.seed(404)
print("Mnemonic 24:", gen_mnemonic(24))

# ---------- Indian ID checksums ----------
# Aadhaar uses Verhoeff checksum algorithm
d_table = [
[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,0,6,7,8,9,5],[2,3,4,0,1,7,8,9,5,6],
[3,4,0,1,2,8,9,5,6,7],[4,0,1,2,3,9,5,6,7,8],[5,9,8,7,6,0,4,3,2,1],
[6,5,9,8,7,1,0,4,3,2],[7,6,5,9,8,2,1,0,4,3],[8,7,6,5,9,3,2,1,0,4],
[9,8,7,6,5,4,3,2,1,0]]
p_table = [
[0,1,2,3,4,5,6,7,8,9],[1,5,7,6,2,8,3,0,9,4],[5,8,0,3,7,9,6,1,4,2],
[8,9,1,6,0,4,3,5,2,7],[9,4,5,3,1,2,6,8,7,0],[4,2,8,6,5,7,3,9,0,1],
[2,7,9,3,8,0,6,4,1,5],[7,0,4,6,9,1,3,2,5,8]]
inv_table = [0,4,3,2,1,5,6,7,8,9]

def verhoeff_generate(num_str):
    c = 0
    reversed_digits = [int(d) for d in reversed(num_str)]
    for i, item in enumerate(reversed_digits):
        c = d_table[c][p_table[(i+1) % 8][item]]
    return inv_table[c]

def gen_aadhaar():
    # Aadhaar: 12 digits total, first digit 2-9, last digit is Verhoeff checksum
    first11 = str(random.randint(2,9)) + ''.join(str(random.randint(0,9)) for _ in range(10))
    check = verhoeff_generate(first11)
    full = first11 + str(check)
    return f"{full[0:4]} {full[4:8]} {full[8:12]}"

random.seed(55)
print("Aadhaar1:", gen_aadhaar())
random.seed(56)
print("Aadhaar2:", gen_aadhaar())
random.seed(57)
print("Aadhaar3:", gen_aadhaar())

# PAN: 5 letters (3 random + 1 category + 1 first letter of surname) + 4 digits + 1 checksum letter (approx format only)
def gen_pan(surname_letter):
    letters = ''.join(random.choice(string.ascii_uppercase) for _ in range(3))
    category = 'P'  # P = individual
    digits = ''.join(str(random.randint(0,9)) for _ in range(4))
    check = random.choice(string.ascii_uppercase)
    return f"{letters}{category}{surname_letter}{digits}{check}"

random.seed(11)
print("PAN1:", gen_pan('D'))  # Delgado-like
random.seed(12)
print("PAN2:", gen_pan('V'))  # Voss-like
random.seed(13)
print("PAN3:", gen_pan('S'))
