mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
Merge pull request #86 from majestrate/vanity
loki vanity address script demo thingy
This commit is contained in:
commit
b9a41e380f
2
contrib/py/vanity/.gitignore
vendored
Normal file
2
contrib/py/vanity/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
*.private
|
112
contrib/py/vanity/bencode.py
Normal file
112
contrib/py/vanity/bencode.py
Normal file
@ -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()
|
136
contrib/py/vanity/lokinet-vanity.py
Normal file
136
contrib/py/vanity/lokinet-vanity.py
Normal file
@ -0,0 +1,136 @@
|
||||
#!/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):
|
||||
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
|
||||
while i > 0:
|
||||
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, prefix, lo, hi, si):
|
||||
print(prefix)
|
||||
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(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()
|
||||
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:])
|
10
contrib/py/vanity/readme.md
Normal file
10
contrib/py/vanity/readme.md
Normal file
@ -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 `^7oki` using 8 cpu threads:
|
||||
|
||||
python3 lokinet-vanity.py keyfile.private 7oki 8
|
1
contrib/py/vanity/requirements.txt
Normal file
1
contrib/py/vanity/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
libnacl
|
Loading…
Reference in New Issue
Block a user