Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Creating a vanity address is a two step process:

Checkout this repository on your machine with `Python 3.9` installed. It is recommended to use some computer with good GPU.

Execute in `src/generator` and replace `<suffix>` with desired suffix name and `<owner>` with an address of a wallet that then could be used for deployment.
Execute in `src/generator` and replace `<suffix>,<suffix2>` with desired suffix names and `<owner>` with an address of a wallet that then could be used for deployment.

```bash
python3.9 run.py --end '<suffix>' -w -1 --case-sensitive <owner>
python3.9 run.py --end '<suffix>,<suffix2>' -w -1 --case-sensitive <owner>
```

Example output:
Expand Down
105 changes: 72 additions & 33 deletions src/generator/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

parser = argparse.ArgumentParser('vanity-generator', description='Generate beautiful wallet for TON on GPU using vanity contract')
parser.add_argument('owner', help='An owner of vanity contract')
parser.add_argument('--end', type=str, default='', help='Search in the end of address')
parser.add_argument('--start', type=str, default='', help='Search in the start of address')
parser.add_argument('--end', type=str, default='', help='Search in the end of address, separated by , or |')
parser.add_argument('--start', type=str, default='', help='Search in the start of address, separated by , or |')
parser.add_argument('-nb', action='store_true', default=False, help='Search for non-bouncable addresses')
parser.add_argument('-t', action='store_true', default=False, help='Search for testnet addresses')
parser.add_argument('--threads', type=int, help='Worker threads')
Expand All @@ -20,17 +20,21 @@
parser.add_argument('--early-prefix', action='store_true', help='Check prefix starting from third character (subject to some address format restrictions, fourth by default)')
parser.add_argument('--only-one', action='store_true', help='Stop when an address is found (runs until interrupted by default)')


args = parser.parse_args()
if not args.end and not args.start:
parser.print_usage()
print('vanity-generator: error: the following arguments are required: end or start')
os._exit(0)

def parse_parameters(param):
return [p.strip() for p in param.replace('|', ',').split(',') if p.strip()]

start_patterns = parse_parameters(args.start)
end_patterns = parse_parameters(args.end)

OWNER = args.owner
owner_decoded = base64.urlsafe_b64decode(OWNER)
inner_base = bytearray.fromhex('00840400') + owner_decoded[2:34]
inner_base = bytearray.fromhex('00840400') + owner_decoded[2:34]

BOUNCEABLE_TAG = 0x11
NON_BOUNCEABLE_TAG = 0x51
Expand All @@ -44,34 +48,69 @@
flags |= WORKCHAIN

if not args.case_sensitive:
args.start = args.start.lower()
args.end = args.end.lower()
start_patterns = [p.lower() for p in start_patterns]
end_patterns = [p.lower() for p in end_patterns]

start_offset = 3

conditions = []
kernel_conditions = []
start_conditions = []
end_conditions = []
if args.early_prefix:
conditions.append('early-prefix')
start_offset = 2
if args.case_sensitive:
conditions.append('case-sensitive')
if args.start:
conditions.append(f'starting with "{args.start}"')
for i, c in enumerate(args.start):
pos = i + start_offset
if args.case_sensitive:
kernel_conditions.append(f"result[{pos}] == '{c}'")
else:
kernel_conditions.append(f"(result[{pos}] == '{c}' || result[{pos}] == '{c.upper()}')")
if args.end:
conditions.append(f'with "{args.end}" in the end')
for i, c in enumerate(args.end):
pos = 47 - len(args.end) + i + 1
if args.case_sensitive:
kernel_conditions.append(f"result[{pos}] == '{c}'")
else:
kernel_conditions.append(f"(result[{pos}] == '{c}' || result[{pos}] == '{c.upper()}')")
if start_patterns:
conditions.append(f"starting with {start_patterns}")
start_conditions.append(
" || ".join(
[
"("
+ " && ".join(
[
(
f"result[{i + start_offset}] == '{c}'"
if args.case_sensitive
else f"(result[{i + start_offset}] == '{c}' || result[{i + start_offset}] == '{c.upper()}')"
)
for i, c in enumerate(pattern)
]
)
+ ")"
for pattern in start_patterns
]
)
)
if end_patterns:
conditions.append(f"with {end_patterns} in the end")
end_conditions.append(
" || ".join(
[
"("
+ " && ".join(
[
(
f"result[{47 - len(pattern) + i + 1}] == '{c}'"
if args.case_sensitive
else f"(result[{47 - len(pattern) + i + 1}] == '{c}' || result[{47 - len(pattern) + i + 1}] == '{c.upper()}')"
)
for i, c in enumerate(pattern)
]
)
+ ")"
for pattern in end_patterns
]
)
)
kernel_conditions = []
if start_conditions and end_conditions:
kernel_conditions.append(f'(({" && ".join(start_conditions)}) && ({" && ".join(end_conditions)}))')
elif start_conditions:
kernel_conditions.append(f'({" && ".join(start_conditions)})')
elif end_conditions:
kernel_conditions.append(f'({" && ".join(end_conditions)})')


print()
print('Searching wallets', ', '.join(conditions))
Expand All @@ -80,7 +119,6 @@
print("Kernel conditions:", ' && '.join(kernel_conditions))
print()


mf = cl.mem_flags
n_found = 0

Expand Down Expand Up @@ -116,20 +154,20 @@ def solver(dev, context, queue, program):
threads = args.threads or (dev.max_work_group_size * dev.max_compute_units)
iterations = args.its
program.hash_main(
queue,
(threads,),
None,
queue,
(threads,),
None,
np.int32(iterations),
np.ushort(flags),
np.int32(71),
main_g,
np.int32(68),
inner_g,
inner_g,
res_g
).wait()
result = np.empty(2048, np.uint32)
cl.enqueue_copy(queue, result, res_g).wait()

ps = list(np.where(result != 0xffffffff))[0]
misses = 0
if len(ps):
Expand All @@ -147,7 +185,7 @@ def solver(dev, context, queue, program):
main[39:71] = hash1

hs = hashlib.sha256(main[:71]).digest()

address = bytearray()
address += flags.to_bytes(2, 'big') # flags
address += hs
Expand All @@ -156,7 +194,9 @@ def solver(dev, context, queue, program):
address[34] = crc[0]
address[35] = crc[1]
found = base64.urlsafe_b64encode(address).decode('utf-8')
if (len(args.end) > 0 and found.lower().endswith(args.end.lower())) or (len(args.start) > 0 and found[start_offset:].lower().startswith(args.start.lower())):

if any(found.lower().endswith(pattern) for pattern in end_patterns) or \
any(found[start_offset:].lower().startswith(pattern) for pattern in start_patterns):
print('Found: ', found, 'salt: ', salt_np.tobytes().hex())
with open('found.txt', 'a') as f:
f.write(f'{found} {salt_np.tobytes().hex()}\n')
Expand All @@ -166,7 +206,7 @@ def solver(dev, context, queue, program):
n_found += 1
else:
misses += 1
print('Speed:', round(threads * iterations / (time.time() - start) / 1e6), 'Mh/s, miss: ' + str(misses) + ', found: ' + str(n_found))
print('Speed:', round(threads * iterations / (time.time() - start) / 1e6), 'Mh/s, miss: ' + str(misses) + ', found: ' + str(n_found))

kernel_code = open(os.path.join(os.path.dirname(__file__), 'vanity.cl')).read()
kernel_code = kernel_code.replace("<<CONDITION>>", ' && '.join(kernel_conditions))
Expand Down Expand Up @@ -199,4 +239,3 @@ def device_thread(device):
print('Interrupted')
stopped = True
os._exit(0)