DILSHAD737 commited on
Commit
d5d7e15
·
1 Parent(s): 5c3b5a4

Update app.py

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