#!/usr/bin/env python3
"""Offline BIP39 English last-word calculator. Standard library only.

Supply the official english.txt (2048 words), SHA256-checked against the
published bitcoin/bips list. Never run with actual wallet secrets online.
"""
import hashlib
from pathlib import Path
import sys

WORDLIST_HASH = '2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda'


def read_wordlist(path):
    data = path.read_bytes()
    if hashlib.sha256(data).hexdigest() != WORDLIST_HASH:
        raise ValueError('Wordlist SHA-256 mismatch: obtain original bitcoin/bips bip-0039/english.txt')
    words = data.decode('utf-8').splitlines()
    if len(words) != 2048 or len(set(words)) != 2048:
        raise ValueError('Expected 2048 unique BIP39 words')
    return words


def valid_last_words(given, wordlist):
    if len(given) not in (11, 23):
        raise ValueError('Enter exactly 11 or 23 English BIP39 words')
    idx = {w: i for i, w in enumerate(wordlist)}
    invalid = [(pos + 1, w) for pos, w in enumerate(given) if w not in idx]
    if invalid:
        raise ValueError('Unknown word(s): ' + ', '.join(f'{pos}:{word}' for pos, word in invalid))
    ent_bits = 128 if len(given) == 11 else 256
    checksum_bits = ent_bits // 32
    extra_entropy_bits = 11 - checksum_bits
    prefix = ''.join(f'{idx[word]:011b}' for word in given)
    out = []
    for extra in range(1 << extra_entropy_bits):
        entropy_binary = prefix + f'{extra:0{extra_entropy_bits}b}'
        entropy = int(entropy_binary, 2).to_bytes(ent_bits // 8, 'big')
        digest_bits = f'{hashlib.sha256(entropy).digest()[0]:08b}'[:checksum_bits]
        last_idx = int(f'{extra:0{extra_entropy_bits}b}' + digest_bits, 2)
        out.append((extra, f'{extra:0{extra_entropy_bits}b}', wordlist[last_idx]))
    return out


def main():
    path = Path(__file__).resolve().with_name('english.txt')
    if not path.exists():
        sys.exit('Missing english.txt alongside script. See README.txt for official link.')
    try:
        wordlist = read_wordlist(path)
        print('BIP39 English final-word calculator — 100% offline, no RNG required.')
        print('Enter 11 or 23 BIP39 words separated by spaces:')
        given = input('> ').strip().lower().split()
        options = valid_last_words(given, wordlist)
    except (ValueError, OSError) as error:
        sys.exit(f'ERROR: {error}')
    print(f'\n{len(options)} checksum-valid last words:')
    for index, bits, word in options:
        print(f'  {bits}  {word}')
    print('\nChoose the option with independent random coin flips:')
    print(f'  {len(options).bit_length()-1} fair flips: heads=1, tails=0; match the displayed bit pattern.')
    print('DO NOT copy your seed into any website. Back up the complete phrase securely.')

if __name__ == '__main__':
    main()
