高级脑钱包生成器 (Brain Wallet Generator)

作者: 达哥 (@btcdage)

什么是高级脑钱包?

高级脑钱包并非简单地将私钥记在脑中,而是一种先进的、基于隐藏规则的私钥管理方案。它利用您独特的、只有您自己知道的一系列信息(如诗词、个人经历、特定日期等)和一套自定义的加密规则(哈希算法、哈希次数、盐值等),来生成独一无二且无法被暴力破解的比特币私钥。

其核心思想在于:“规则”本身就是最高级别的机密。即使部分“脑口令”泄露,只要生成私钥的完整规则不为人知,您的资产依然安全无虞。

核心原理与优势

软件主界面预览

高级脑钱包生成器主界面截图
源码地址 (Github) 下载可执行文件v0.2.1 (Github) 本地下载v0.2.1 (备用)

离线工具源码 (v0.2.1)

本工具完全开源,您可以在Github上审查每一行代码。我们强烈建议您在完全离线的电脑上运行此工具,以确保您的私钥安全。

运行源码所需依赖 (requirements.txt)

如果您选择从源码运行,请先确保您的Python环境中已安装以下库。您可以使用 `pip` 命令一键安装:

pip install Pillow qrcode bip_utils bitcoinlib
# BrainWalletGenerator v0.2.1 by @btcdage
import tkinter as tk
from tkinter import ttk, Canvas, Scrollbar, messagebox
from hashlib import sha256
from bip_utils import Bip39SeedGenerator, Bip84, Bip84Coins
from bitcoinlib.mnemonic import Mnemonic
from bitcoinlib.keys import HDKey, Address, Key
import threading

def copy_to_clipboard(text_widget):
    text = text_widget.get("1.0", tk.END).strip()
    root.clipboard_clear()
    root.clipboard_append(text)
    root.update()

def clear_all_results():
    results_text.config(state=tk.NORMAL)
    results_text.delete("1.0", tk.END)
    results_text.config(state=tk.DISABLED)

    update_text_entry(hex_entry, "")
    update_text_entry(hash_entry, "")
    update_text_entry(mnemonic_entry, "", readonly=False)


def validate_hash_times(new_value):
    if new_value == "":
         return True
    try:
        value = int(new_value)
        if 1 <= value <= 10000:
            return True
        else:
            return False
    except ValueError:
        return False
def validate_generate_count(new_value):
    if new_value == "":
         return True
    try:
        value = int(new_value)
        if 1 <= value <= 1000:
            return True
        else:
            return False
    except ValueError:
        return False

def update_text_entry(entry_widget, text, readonly=True):
    entry_widget.config(state='normal')
    entry_widget.delete(1.0, "end")
    entry_widget.insert(1.0, text)
    if readonly:
        entry_widget.config(state='disabled')

def create_readonly_entry(label_text_cn, label_text_en, frame):
    label = ttk.Label(frame, text=f"{label_text_en} / {label_text_cn}")
    label.pack(anchor='center')
    entry_frame = tk.Frame(frame)
    entry_frame.pack(fill='x', expand=True)
    if "BIP39" in label_text_en:
        text_entry_height = 3
        text_entry = tk.Text(entry_frame, height=text_entry_height,  width=80, wrap="word")
    else:
        text_entry_height = 1
        text_entry = tk.Text(entry_frame, height=text_entry_height,  width=80, bg='#f0f0f0', wrap="word")
        text_entry.config(state='disabled')
    text_entry.pack(side='left', expand=True)
    copy_button = ttk.Button(entry_frame, text='Copy / 复制', command=lambda: copy_to_clipboard(text_entry))
    copy_button.pack(side='left', padx=5)

    return text_entry

def generate_addresses(mnemonic_words, count):
    output_text = ""

    hdkey = HDKey.from_passphrase(mnemonic_words, network='bitcoin')
    private_key = hdkey.private_hex
    key = Key(import_key=private_key)
    private_key_wif = key.wif()
    private_key_bech32 = "p2wpkh:" + private_key_wif
    public_key_hex = hdkey.public_hex
    address_p2pkh = Address(hdkey.public_hex, encoding='base58', script_type='p2pkh').address
    address_bech32 = Address(hdkey.public_hex, encoding='bech32', script_type='p2wpkh').address

    output_text += f"1. 私钥: {private_key_wif}\n"
    output_text += f"2. 公钥: {public_key_hex}\n"
    output_text += f"3. P2PKH地址: {address_p2pkh}\n"
    output_text += f"4. Bech32私钥: {private_key_bech32}\n"
    output_text += f"5. Bech32地址: {address_bech32}\n"

    for i in range(1, count):
        seed_str = mnemonic_words + f"[{i}]"
        hash_result = sha256(seed_str.encode('utf-8')).hexdigest()

        mnemo = Mnemonic('english')
        mnemonic_words_new = mnemo.to_mnemonic(hash_result)
        hdkey = HDKey.from_passphrase(mnemonic_words_new, network='bitcoin')
        private_key = hdkey.private_hex
        key = Key(import_key=private_key)
        private_key_wif = key.wif()
        private_key_bech32 = "p2wpkh:" + private_key_wif
        public_key_hex = hdkey.public_hex
        address_p2pkh = Address(hdkey.public_hex, encoding='base58', script_type='p2pkh').address
        address_bech32 = Address(hdkey.public_hex, encoding='bech32', script_type='p2wpkh').address

        base_line_number = (i * 5) + 1
        output_text += f"{base_line_number}. 私钥: {private_key_wif}\n"
        output_text += f"{base_line_number + 1}. 公钥: {public_key_hex}\n"
        output_text += f"{base_line_number + 2}. P2PKH地址: {address_p2pkh}\n"
        output_text += f"{base_line_number + 3}. Bech32私钥: {private_key_bech32}\n"
        output_text += f"{base_line_number + 4}. Bech32地址: {address_bech32}\n"
    return output_text

def generate_from_mnemonic_thread():
    results_text.config(state=tk.NORMAL)
    results_text.insert("1.0", "正在生成...\n")
    results_text.config(state=tk.DISABLED)
    mnemonic_words = mnemonic_entry.get("1.0", tk.END).strip()
    if not mnemonic_words:
        results_text.config(state=tk.NORMAL)
        results_text.delete("1.0", tk.END)
        results_text.config(state=tk.DISABLED)
        messagebox.showerror("错误", "助记词不能为空")
        return

    count_str = generate_count_entry.get()
    if not count_str:
        results_text.config(state=tk.NORMAL)
        results_text.delete("1.0", tk.END)
        results_text.config(state=tk.DISABLED)
        messagebox.showerror("错误", "请输入生成数量")
        return
    try:
        count = int(count_str)
        if not 1 <= count <= 1000:
           results_text.config(state=tk.NORMAL)
           results_text.delete("1.0", tk.END)
           results_text.config(state=tk.DISABLED)
           messagebox.showerror("错误", "生成数量必须是1到1000的整数")
           return
    except ValueError:
        results_text.config(state=tk.NORMAL)
        results_text.delete("1.0", tk.END)
        results_text.config(state=tk.DISABLED)
        messagebox.showerror("错误", "生成数量必须是整数")
        return

    output_text = generate_addresses(mnemonic_words, count)

    results_text.config(state=tk.NORMAL)
    results_text.delete("1.0", tk.END)
    results_text.insert("1.0", output_text)
    results_text.config(state=tk.DISABLED)

def generate_from_mnemonic():
    threading.Thread(target=generate_from_mnemonic_thread).start()


def generate_brain_wallet_thread():
    clear_all_results()
    results_text.config(state=tk.NORMAL)
    results_text.insert("1.0", "正在生成...\n")
    results_text.config(state=tk.DISABLED)
    passphrase = passphrase_entry.get()
    salt = salt_entry.get()
    hash_times_str = hash_times_entry.get()
    if not hash_times_str:
        results_text.config(state=tk.NORMAL)
        results_text.delete("1.0", tk.END)
        results_text.config(state=tk.DISABLED)
        messagebox.showerror("错误", "请输入哈希次数")
        return

    try:
      hash_times = int(hash_times_str)
      if not 1 <= hash_times <= 10000:
          results_text.config(state=tk.NORMAL)
          results_text.delete("1.0", tk.END)
          results_text.config(state=tk.DISABLED)
          messagebox.showerror("错误", "哈希次数必须是1到10000的整数")
          return
    except ValueError:
      results_text.config(state=tk.NORMAL)
      results_text.delete("1.0", tk.END)
      results_text.config(state=tk.DISABLED)
      messagebox.showerror("错误", "哈希次数必须是整数")
      return

    for _ in range(hash_times):
        if salt:
            passphrase = passphrase + salt
        bytes_passphrase = passphrase.encode('utf-8')
        hash_result = sha256(bytes_passphrase).hexdigest()
        passphrase = hash_result
    hex_passphrase = "0x" + bytes_passphrase.hex()
    mnemo = Mnemonic('english')
    mnemonic_words = mnemo.to_mnemonic(hash_result)
    update_text_entry(hex_entry, hex_passphrase)
    update_text_entry(hash_entry, hash_result)
    update_text_entry(mnemonic_entry, mnemonic_words, readonly=False)

    count_str = generate_count_entry.get()
    if not count_str:
        return
    try:
        count = int(count_str)
        if not 1 <= count <= 1000:
            return
    except ValueError:
        return
    output_text = generate_addresses(mnemonic_words, count)
    results_text.config(state=tk.NORMAL)
    results_text.delete("1.0", tk.END)
    results_text.insert("1.0", output_text)
    results_text.config(state=tk.DISABLED)

def generate_brain_wallet():
    threading.Thread(target=generate_brain_wallet_thread).start()

root = tk.Tk()
root.title("Brain Wallet Generator by @btcdage / 脑钱包生成器 by 达哥(@btcdage)")
root.geometry("700x600")

title_label = ttk.Label(root, text="Brain Wallet Generator V0.2.1/ 比特币脑钱包生成器 V0.2.1", font=("Arial", 16), anchor='center')
title_label.pack(side="top", pady=5)
title_label1 = ttk.Label(root, text="请使用高级脑而不是直接使用一维脑钱包-达哥(@btcdage)", font=("Arial", 8), anchor='center')
title_label1.pack(side="top", pady=3)
title_label2 = ttk.Label(root, text="Please use advanced brain instead of directly using a one-dimensional brain wallet - @btcdage.", font=("Arial", 8), anchor='center')
title_label2.pack(side="top", pady=10)

main_frame = ttk.Frame(root, padding=10)
main_frame.pack(fill="both", expand=True)

# Passphrase Label and Entry
passphrase_frame = ttk.Frame(main_frame)
passphrase_frame.pack(side="top", fill='x')

passphrase_label = ttk.Label(passphrase_frame, text="Passphrase / 脑口令:")
passphrase_label.pack(side="left", pady=3, padx=5)
passphrase_entry = ttk.Entry(passphrase_frame, width=60)
passphrase_entry.pack(side="left", pady=3, padx=5, fill='x', expand=True)

salt_frame = ttk.Frame(main_frame)
salt_frame.pack(side="top", fill='x')

salt_label = ttk.Label(salt_frame, text="Salt / 加盐:")
salt_label.pack(side="left", pady=3, padx=5)
salt_entry = ttk.Entry(salt_frame, width=60)
salt_entry.pack(side="left", pady=3, padx=5, fill='x', expand=True)


hash_generate_frame = ttk.Frame(main_frame)
hash_generate_frame.pack(side="top", fill='x')


hash_times_label = ttk.Label(hash_generate_frame, text="Hash Times / 哈希次数 (1-10000):")
hash_times_label.pack(side="left", pady=3, padx=5)
hash_times_entry = ttk.Entry(hash_generate_frame, width=10, validate="key")
hash_times_entry['validatecommand'] = (hash_times_entry.register(validate_hash_times), '%P')
hash_times_entry.pack(side="left", pady=3, padx=5)
hash_times_entry.insert(0, "1")

generate_count_label = ttk.Label(hash_generate_frame, text="Generate Count / 生成数量(1-1000):")
generate_count_label.pack(side="left", pady=3, padx=5)
generate_count_entry = ttk.Entry(hash_generate_frame, width=10, validate="key")
generate_count_entry['validatecommand'] = (generate_count_entry.register(validate_generate_count), '%P')
generate_count_entry.pack(side="left", pady=3, padx=5)
generate_count_entry.insert(0, "1")


button_frame = ttk.Frame(main_frame)
button_frame.pack(side="top", pady=3, fill='x')

generate_button = ttk.Button(button_frame, text="Generate Brain Wallet / 开始计算", command=generate_brain_wallet)
generate_button.pack(side="left", pady=3, padx=5)
clear_button = ttk.Button(button_frame, text="Clear All / 清空所有", command=clear_all_results)
clear_button.pack(side="left", pady=10, padx=5)


hex_entry_frame = ttk.Frame(main_frame)
hex_entry_frame.pack(fill='x', padx=10, pady=5)
hex_entry = create_readonly_entry("字节化","Hexadecimal Encoding:", hex_entry_frame)

hash_entry_frame = ttk.Frame(main_frame)
hash_entry_frame.pack(fill='x', padx=10, pady=5)
hash_entry = create_readonly_entry("SHA-256哈希:","SHA-256 Hash:", hash_entry_frame)

mnemonic_entry_frame = ttk.Frame(main_frame)
mnemonic_entry_frame.pack(fill='x', padx=10, pady=5)
mnemonic_entry = create_readonly_entry("BIP39助记词","BIP39 Mnemonic Words:", mnemonic_entry_frame)

mnemonic_button_frame = ttk.Frame(main_frame)
mnemonic_button_frame.pack(fill="x", pady=5)

generate_from_mnemonic_button = ttk.Button(mnemonic_button_frame, text="Generate from mnemonic / 根据助记词生成", command=generate_from_mnemonic)
generate_from_mnemonic_button.pack(side='left', padx=5)

copy_results_button = ttk.Button(mnemonic_button_frame, text='Copy bitcoin Keys /复制结果', command=lambda: copy_to_clipboard(results_text))
copy_results_button.pack(side='left', padx=5)



results_text_frame = tk.Frame(main_frame)
results_text_frame.pack(fill='both', expand=True, padx=10)

results_text = tk.Text(results_text_frame, height=10, width=100, wrap="word")
results_text.config(state='disabled')
results_text.pack(side='left', fill='both', expand=True,  )

results_scrollbar = Scrollbar(results_text_frame, command=results_text.yview)
results_scrollbar.pack(side='right', fill='y')
results_text.config(yscrollcommand=results_scrollbar.set)

root.mainloop()