DILSHAD737 commited on
Commit
83f33ac
·
1 Parent(s): 22aa86c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +231 -2
app.py CHANGED
@@ -1,2 +1,231 @@
1
- import bip39
2
- print(dir(bip39))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from itertools import permutations, combinations
2
+ import hashlib, hmac, os, time, math, gc
3
+ from multiprocessing import Pool
4
+ from eth_account import Account
5
+ import coincurve
6
+ from eth_utils import keccak, to_checksum_address
7
+
8
+ # ============================================================
9
+ words = [
10
+ "lesson", "cushion", "crane", "affair", "federal",
11
+ "decline", "limb", "spend", "reunion", "chief", "cart", "zebra",
12
+ ]
13
+
14
+ PHRASE_MODE = "order"
15
+ USE_BIP39 = True
16
+ BIP39_PASSPHRASE = ""
17
+ HD_DERIVATION = True
18
+ ADDRESS_INDEX = 0
19
+ CHECK_BIP39_CHECKSUM = False # ✅ prefilter off — speed 16x
20
+ ADDRESSES_FILE = "12730802_addresses.csv"
21
+ MATCHED_FILE = f"matched_keys_{PHRASE_MODE}.txt"
22
+ BATCH_SIZE = 5000
23
+ NUM_WORKERS = 48
24
+ CHUNK_SIZE = 4
25
+ # ============================================================
26
+
27
+ # ---------- secp256k1 ----------
28
+ _SECP256K1_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
29
+ _HARDENED = 0x80000000
30
+
31
+ def _bip32_derive_child_priv(parent_priv, parent_chain, index):
32
+ if index >= _HARDENED:
33
+ data = b'\x00' + parent_priv + index.to_bytes(4, 'big')
34
+ else:
35
+ pub = coincurve.PrivateKey(parent_priv).public_key.format(compressed=True)
36
+ data = pub + index.to_bytes(4, 'big')
37
+ I = hmac.new(parent_chain, data, hashlib.sha512).digest()
38
+ child_int = (int.from_bytes(I[:32], 'big') + int.from_bytes(parent_priv, 'big')) % _SECP256K1_N
39
+ if child_int == 0:
40
+ raise ValueError("Invalid child key")
41
+ return child_int.to_bytes(32, 'big'), I[32:]
42
+
43
+ def seed_to_privkey_hd(seed, address_index=0):
44
+ I = hmac.new(b"Bitcoin seed", seed, hashlib.sha512).digest()
45
+ key, chain = I[:32], I[32:]
46
+ path = [44 + _HARDENED, 60 + _HARDENED, _HARDENED, 0, address_index]
47
+ for idx in path:
48
+ key, chain = _bip32_derive_child_priv(key, chain, idx)
49
+ return key
50
+
51
+ # ---------- BIP39 (flexible) ----------
52
+ try:
53
+ import bip39 as _bip39_rust
54
+ _USE_RUST_BIP39 = True
55
+ # Function name detect karein
56
+ if hasattr(_bip39_rust, 'bip39_to_seed'):
57
+ _seed_fn = _bip39_rust.bip39_to_seed
58
+ _check_fn = getattr(_bip39_rust, 'bip39_validate', None)
59
+ elif hasattr(_bip39_rust, 'phrase_to_seed'):
60
+ _seed_fn = _bip39_rust.phrase_to_seed
61
+ _check_fn = getattr(_bip39_rust, 'check_phrase', None)
62
+ elif hasattr(_bip39_rust, 'bip39_mnemonic_to_seed'):
63
+ _seed_fn = _bip39_rust.bip39_mnemonic_to_seed
64
+ _check_fn = getattr(_bip39_rust, 'bip39_mnemonic_to_entropy', None)
65
+ else:
66
+ _seed_fn = None
67
+ _check_fn = None
68
+ _USE_RUST_BIP39 = False
69
+ except ImportError:
70
+ _bip39_rust = None
71
+ _USE_RUST_BIP39 = False
72
+ _seed_fn = None
73
+ _check_fn = None
74
+
75
+ _MNEMONIC = None
76
+
77
+ def _get_mnemonic():
78
+ global _MNEMONIC
79
+ if _MNEMONIC is None:
80
+ from mnemonic import Mnemonic
81
+ _MNEMONIC = Mnemonic("english")
82
+ return _MNEMONIC
83
+
84
+ def is_valid_bip39(phrase):
85
+ if _USE_RUST_BIP39 and _check_fn:
86
+ try:
87
+ _check_fn(phrase)
88
+ return True
89
+ except Exception:
90
+ return False
91
+ return _get_mnemonic().check(phrase)
92
+
93
+ def phrase_to_seed(phrase):
94
+ if _USE_RUST_BIP39 and _seed_fn:
95
+ return _seed_fn(phrase, BIP39_PASSPHRASE)
96
+ return _get_mnemonic().to_seed(phrase, passphrase=BIP39_PASSPHRASE)
97
+
98
+ # ---------- Address file ----------
99
+ def load_addresses(path):
100
+ s = set()
101
+ with open(path, "r", encoding="utf-8") as f:
102
+ for line in f:
103
+ a = line.strip().strip('"').strip("'").lstrip("\ufeff").lower()
104
+ if a.startswith("0x"):
105
+ a = a[2:]
106
+ if a and len(a) == 40:
107
+ s.add(a)
108
+ return frozenset(s)
109
+
110
+ def normalize(addr):
111
+ a = addr.strip().lower()
112
+ if a.startswith("0x"):
113
+ a = a[2:]
114
+ return a
115
+
116
+ # ---------- Generator ----------
117
+ def generate_phrases():
118
+ n = len(words)
119
+ if PHRASE_MODE == "order":
120
+ for perm in permutations(words):
121
+ yield " ".join(perm)
122
+ elif PHRASE_MODE == "replace":
123
+ for i in range(n):
124
+ for w in words:
125
+ new = words.copy()
126
+ new[i] = w
127
+ yield " ".join(new)
128
+ elif PHRASE_MODE == "subset":
129
+ for r in range(1, n + 1):
130
+ for combo in combinations(words, r):
131
+ yield " ".join(combo)
132
+
133
+ def count_total():
134
+ n = len(words)
135
+ if PHRASE_MODE == "order": return math.factorial(n)
136
+ if PHRASE_MODE == "replace": return n * n
137
+ if PHRASE_MODE == "subset": return 2**n - 1
138
+
139
+ # ---------- Worker ----------
140
+ _KNOWN = None
141
+
142
+ def init_worker(known):
143
+ global _KNOWN
144
+ _KNOWN = known
145
+ _get_mnemonic()
146
+
147
+ def process_batch(batch):
148
+ hits = []
149
+ known = _KNOWN
150
+ for phrase in batch:
151
+ if CHECK_BIP39_CHECKSUM and not is_valid_bip39(phrase):
152
+ continue
153
+ try:
154
+ seed = phrase_to_seed(phrase) # ✅ bip39_to_seed (Rust)
155
+ if HD_DERIVATION:
156
+ priv = seed_to_privkey_hd(seed, ADDRESS_INDEX)
157
+ else:
158
+ priv = seed[:32]
159
+ pub = coincurve.PrivateKey(priv).public_key.format(compressed=False)[1:]
160
+ addr = to_checksum_address(keccak(pub)[-20:])
161
+ except Exception:
162
+ continue
163
+ if normalize(addr) in known:
164
+ hits.append((phrase, priv.hex(), addr))
165
+ return hits
166
+
167
+ def batch_generator():
168
+ batch = []
169
+ for phrase in generate_phrases():
170
+ batch.append(phrase)
171
+ if len(batch) >= BATCH_SIZE:
172
+ yield batch
173
+ batch = []
174
+ if batch:
175
+ yield batch
176
+
177
+ # ---------- Main ----------
178
+ def main():
179
+ if not os.path.exists(ADDRESSES_FILE):
180
+ raise SystemExit(f"File nahi mili: {ADDRESSES_FILE}")
181
+
182
+ total = count_total()
183
+ print(f"\nMode: {PHRASE_MODE} | Total: {total:,} | Workers: {NUM_WORKERS}")
184
+ print(f"HD: {HD_DERIVATION} (index {ADDRESS_INDEX})")
185
+ print(f"Checksum prefilter: {CHECK_BIP39_CHECKSUM}")
186
+ print(f"Rust BIP39: {_USE_RUST_BIP39} ({'bip39_to_seed' if _seed_fn and _USE_RUST_BIP39 else 'fallback'})\n")
187
+
188
+ known = load_addresses(ADDRESSES_FILE)
189
+ print(f"Loaded {len(known):,} addresses\n")
190
+
191
+ matches = []
192
+ done = 0
193
+ start = time.time()
194
+ last_log = start
195
+
196
+ with open(MATCHED_FILE, "w", encoding="utf-8") as f:
197
+ f.write("")
198
+
199
+ gc.collect()
200
+ gc.freeze()
201
+
202
+ with Pool(processes=NUM_WORKERS,
203
+ initializer=init_worker,
204
+ initargs=(known,)) as pool:
205
+ for hits in pool.imap_unordered(process_batch, batch_generator(), chunksize=CHUNK_SIZE):
206
+ done += BATCH_SIZE
207
+ for phrase, key_hex, addr in hits:
208
+ print(f"\n✅ MATCH: {phrase}\n priv: {key_hex}\n addr: {addr}\n")
209
+ matches.append((phrase, key_hex, addr))
210
+ with open(MATCHED_FILE, "a", encoding="utf-8") as f:
211
+ f.write(f"{phrase} | {key_hex} | {addr}\n")
212
+ f.flush()
213
+ os.fsync(f.fileno())
214
+
215
+ now = time.time()
216
+ if now - last_log >= 2:
217
+ elapsed = now - start
218
+ rate = done / elapsed if elapsed else 0
219
+ eta = (total - done) / rate if rate else 0
220
+ print(f" ...{done:,}/{total:,} ({100*done/total:.2f}%) "
221
+ f"{rate:,.0f}/s ETA {eta/60:.1f}min")
222
+ last_log = now
223
+
224
+ elapsed = time.time() - start
225
+ print(f"\nDone {elapsed/60:.2f} min. {len(matches)} match(es).")
226
+ if matches:
227
+ print(f"Results: {MATCHED_FILE}")
228
+
229
+
230
+ if __name__ == "__main__":
231
+ main()