From 93498bf78e43354356f991a56266df6d2f2f2db1 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Nov 2018 09:03:07 -0500 Subject: [PATCH 1/4] lokinet address vanity generator --- contrib/py/vanity/.gitignore | 2 + contrib/py/vanity/bencode.py | 112 ++++++++++++++++++++++++ contrib/py/vanity/lokinet-vanity.py | 131 ++++++++++++++++++++++++++++ contrib/py/vanity/readme.md | 10 +++ contrib/py/vanity/requirements.txt | 1 + 5 files changed, 256 insertions(+) create mode 100644 contrib/py/vanity/.gitignore create mode 100644 contrib/py/vanity/bencode.py create mode 100644 contrib/py/vanity/lokinet-vanity.py create mode 100644 contrib/py/vanity/readme.md create mode 100644 contrib/py/vanity/requirements.txt diff --git a/contrib/py/vanity/.gitignore b/contrib/py/vanity/.gitignore new file mode 100644 index 000000000..8e5737fb0 --- /dev/null +++ b/contrib/py/vanity/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +*.private \ No newline at end of file diff --git a/contrib/py/vanity/bencode.py b/contrib/py/vanity/bencode.py new file mode 100644 index 000000000..5c131fc9b --- /dev/null +++ b/contrib/py/vanity/bencode.py @@ -0,0 +1,112 @@ +# +# super freaking dead simple wicked awesome bencode library +# +from io import BytesIO + +class BCodec: + encoding = 'utf-8' + def __init__(self, fd): + self._fd = fd + + def _write_bytestring(self, bs): + self._fd.write('{}:'.format(len(bs)).encode('ascii')) + self._fd.write(bs) + + def _write_list(self, l): + self._fd.write(b'l') + for item in l: + self.encode(item) + self._fd.write(b'e') + + def _write_dict(self, d): + self._fd.write(b'd') + keys = list(d.keys()) + keys.sort() + for k in keys: + if isinstance(k, str): + self._write_bytestring(k.encode(self.encoding)) + elif isinstance(k, bytes): + self._write_bytestring(k) + else: + self._write_bytestring('{}'.format(k).encode(self.encoding)) + self.encode(d[k]) + self._fd.write(b'e') + + def _write_int(self, i): + self._fd.write('i{}e'.format(i).encode(self.encoding)) + + def encode(self, obj): + if isinstance(obj, dict): + self._write_dict(obj) + elif isinstance(obj, list): + self._write_list(obj) + elif isinstance(obj, int): + self._write_int(obj) + elif isinstance(obj, str): + self._write_bytestring(obj.encode(self.encoding)) + elif isinstance(obj, bytes): + self._write_bytestring(obj) + elif hasattr(obj, bencode): + obj.bencode(self._fd) + else: + raise ValueError("invalid object type") + + def _readuntil(self, delim): + b = bytes() + while True: + ch = self._fd.read(1) + if ch == delim: + return b + b += ch + + def _decode_list(self): + l = list() + while True: + b = self._fd.read(1) + if b == b'e': + return l + l.append(self._decode(b)) + + def _decode_dict(self): + d = dict() + while True: + ch = self._fd.read(1) + if ch == b'e': + return d + k = self._decode_bytestring(ch) + d[k] = self.decode() + + def _decode_int(self): + return int(self._readuntil(b'e'), 10) + + def _decode_bytestring(self, ch): + ch += self._readuntil(b':') + l = int(ch, base=10) + return self._fd.read(l) + + def _decode(self, ch): + if ch == b'd': + return self._decode_dict() + elif ch == b'l': + return self._decode_list() + elif ch == b'i': + return self._decode_int() + elif ch in [b'0',b'1',b'2',b'3',b'4',b'5',b'6',b'7',b'8',b'9']: + return self._decode_bytestring(ch) + else: + raise ValueError(ch) + + def decode(self): + return self._decode(self._fd.read(1)) + + +def bencode(obj): + buf = BytesIO() + b = BCodec(buf) + b.encode(obj) + return buf.bytes() + +def bdecode(bytestring): + buf = BytesIO() + buf.write(bytestring) + return BCodec(buf).decode() \ No newline at end of file diff --git a/contrib/py/vanity/lokinet-vanity.py b/contrib/py/vanity/lokinet-vanity.py new file mode 100644 index 000000000..750ee427e --- /dev/null +++ b/contrib/py/vanity/lokinet-vanity.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +import bencode +import sys +import libnacl +import base64 +import struct +from io import BytesIO +import time +from multiprocessing import Process, Array, Value + + + +def print_help(): + print('usage: {} keyfile.private prefix numthreads'.format(sys.argv[0])) + return 1 + +_zalpha = ['y', 'b', 'n', 'd', 'r', 'f', 'g', '8', + 'e', 'j', 'k', 'm', 'c', 'p', 'q', 'x', + 'o', 't', '1', 'u', 'w', 'i', 's', 'z', + 'a', '3', '4', '5', 'h', '7', '6', '9'] + +def zb32_encode(buf): + s = str() + bits = 0 + l = len(buf) + idx = 0 + tmp = buf[idx] + while bits > 0 or idx < l: + if bits < 5: + if idx < l: + tmp <<= 8 + tmp |= buf[idx] & 0xff + idx += 1 + bits += 8 + else: + tmp <<= 5 - bits + bits = 5 + bits -= 5 + s += _zalpha[(tmp >> bits) & 0x1f] + return s + + +def _gen_si(keys): + e = keys[b'e'][32:] + s = keys[b's'][32:] + v = keys[b'v'] + return {'e': e, 's':s, 'v':v} + + +class AddrGen: + + def __init__(self, threads, keys, prefix): + self._inc = threads + self._keys = keys + self._c = Value('i') + self.sync = Array('i', 3) + self._procs = [] + self.prefix = prefix + + def runit(self): + i = self._inc + hi = abs(libnacl.randombytes_random()) + lo = abs(libnacl.randombytes_random()) + while i > 0: + p = Process(target=self._gen_addr_tick, args=(lo+i, hi+i, _gen_si(self._keys))) + p.start() + self._procs.append(p) + i -=1 + return self._runner() + + def _gen_addr_tick(self, lo, hi, si): + fd = BytesIO() + addr = '' + enc = bencode.BCodec(fd) + while self.sync[2] == 0: + si['x'] = struct.pack('>QQ', lo, hi) + fd.seek(0,0) + enc.encode(si) + pub = bytes(fd.getbuffer()) + addr = zb32_encode(libnacl.crypto_generichash(pub)) + if addr.startswith(self.prefix): + self.sync[2] = 1 + self.sync[0] = hi + self.sync[1] = lo + return + hi += self._inc + if hi == 0: + lo += 1 + self._c.value += 1 + + def _print_stats(self): + print('{} H/s'.format(self._c.value)) + self._c.value = 0 + + def _joinall(self): + for p in self._procs: + p.join() + + def _runner(self): + while self.sync[2] == 0: + time.sleep(1) + self._print_stats() + self._joinall() + fd = BytesIO() + enc = bencode.BCodec(fd) + hi = self.sync[0] + lo = self.sync[1] + si = _gen_si(self._keys) + si['x'] = struct.pack('>QQ', lo, hi) + enc.encode(si) + pub = bytes(fd.getbuffer()) + addr = zb32_encode(libnacl.crypto_generichash(pub)) + return si['x'], addr + + +def main(args): + if len(args) != 3: + return print_help() + keys = None + with open(args[0], 'rb') as fd: + dec = bencode.BCodec(fd) + keys = dec.decode() + runner = AddrGen(int(args[2]), keys, args[1]) + keys[b'x'], addr = runner.runit() + print("found {}.loki".format(addr)) + with open(args[0], 'wb') as fd: + enc = bencode.BCodec(fd) + enc.encode(keys) + +if __name__ == '__main__': + main(sys.argv[1:]) \ No newline at end of file diff --git a/contrib/py/vanity/readme.md b/contrib/py/vanity/readme.md new file mode 100644 index 000000000..dc10e820f --- /dev/null +++ b/contrib/py/vanity/readme.md @@ -0,0 +1,10 @@ +# lokinet vanity address generator + +installing deps: + + sudo apt install libsodium-dev + pip3 install --user -r requirements.txt + +to generate a nonce with a prefix `^loki` using 8 cpu threads: + + python3 lokinet-vanity.py keyfile.private loki 8 \ No newline at end of file diff --git a/contrib/py/vanity/requirements.txt b/contrib/py/vanity/requirements.txt new file mode 100644 index 000000000..15d991e7b --- /dev/null +++ b/contrib/py/vanity/requirements.txt @@ -0,0 +1 @@ +libnacl \ No newline at end of file From 97ddf00cb3a67335b90be26a3ee5725cde05ec39 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Nov 2018 09:10:27 -0500 Subject: [PATCH 2/4] update vanity script, check for valid chars --- contrib/py/vanity/lokinet-vanity.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/contrib/py/vanity/lokinet-vanity.py b/contrib/py/vanity/lokinet-vanity.py index 750ee427e..00b3f8bd0 100644 --- a/contrib/py/vanity/lokinet-vanity.py +++ b/contrib/py/vanity/lokinet-vanity.py @@ -58,17 +58,21 @@ class AddrGen: self.prefix = prefix def runit(self): + for ch in self.prefix: + if ch not in _zalpha: + print("invalid prefix, {} not a valid character".format(ch)) + return None, None + print("find ^{}.loki".format(self.prefix)) i = self._inc - hi = abs(libnacl.randombytes_random()) - lo = abs(libnacl.randombytes_random()) while i > 0: - p = Process(target=self._gen_addr_tick, args=(lo+i, hi+i, _gen_si(self._keys))) + p = Process(target=self._gen_addr_tick, args=(self.prefix, abs(libnacl.randombytes_random()), abs(libnacl.randombytes_random()), _gen_si(self._keys))) p.start() self._procs.append(p) i -=1 return self._runner() - def _gen_addr_tick(self, lo, hi, si): + def _gen_addr_tick(self, prefix, lo, hi, si): + print(prefix) fd = BytesIO() addr = '' enc = bencode.BCodec(fd) @@ -78,7 +82,8 @@ class AddrGen: enc.encode(si) pub = bytes(fd.getbuffer()) addr = zb32_encode(libnacl.crypto_generichash(pub)) - if addr.startswith(self.prefix): + if addr.startswith(prefix): + print(addr) self.sync[2] = 1 self.sync[0] = hi self.sync[1] = lo @@ -122,10 +127,11 @@ def main(args): keys = dec.decode() runner = AddrGen(int(args[2]), keys, args[1]) keys[b'x'], addr = runner.runit() - print("found {}.loki".format(addr)) - with open(args[0], 'wb') as fd: - enc = bencode.BCodec(fd) - enc.encode(keys) + if addr: + print("found {}.loki".format(addr)) + with open(args[0], 'wb') as fd: + enc = bencode.BCodec(fd) + enc.encode(keys) if __name__ == '__main__': main(sys.argv[1:]) \ No newline at end of file From 72d8a152610b2cd5ba195fcb50762746cd53b5df Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Nov 2018 09:11:43 -0500 Subject: [PATCH 3/4] remove uneeded print --- contrib/py/vanity/lokinet-vanity.py | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/py/vanity/lokinet-vanity.py b/contrib/py/vanity/lokinet-vanity.py index 00b3f8bd0..09dc061ff 100644 --- a/contrib/py/vanity/lokinet-vanity.py +++ b/contrib/py/vanity/lokinet-vanity.py @@ -83,7 +83,6 @@ class AddrGen: pub = bytes(fd.getbuffer()) addr = zb32_encode(libnacl.crypto_generichash(pub)) if addr.startswith(prefix): - print(addr) self.sync[2] = 1 self.sync[0] = hi self.sync[1] = lo From 2b810e770c951909fd745e359d1af2b42b281323 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Nov 2018 09:25:17 -0500 Subject: [PATCH 4/4] update example --- contrib/py/vanity/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/py/vanity/readme.md b/contrib/py/vanity/readme.md index dc10e820f..8c2203309 100644 --- a/contrib/py/vanity/readme.md +++ b/contrib/py/vanity/readme.md @@ -5,6 +5,6 @@ installing deps: sudo apt install libsodium-dev pip3 install --user -r requirements.txt -to generate a nonce with a prefix `^loki` using 8 cpu threads: +to generate a nonce with a prefix `^7oki` using 8 cpu threads: - python3 lokinet-vanity.py keyfile.private loki 8 \ No newline at end of file + python3 lokinet-vanity.py keyfile.private 7oki 8 \ No newline at end of file