def block_data( self, data=None ): # if no data = last block ([-1]) #change this to add error.. error = { 'status': 'error', 'error': 'block not found', 'method': 'block_data', 'parameter': data } logger.info(('<<< API block data call', data)) if not data: data = self.factory.chain.m_get_last_block() data1 = copy.deepcopy(data) data1.status = 'ok' return helper.json_print_telnet(data1) try: int(data) # is the data actually a number? except: return helper.json_print_telnet(error) js_bk = self.factory.chain.m_get_block(int(data)) if js_bk == False: return helper.json_print_telnet(error) else: js_bk1 = copy.deepcopy(js_bk) js_bk1.status = 'ok' js_bk1.blockheader.block_reward = js_bk1.blockheader.block_reward / 100000000.000000000 return helper.json_print_telnet(js_bk1)
def dataReceived(self, data): self.factory.recn += 1 self.isJSON = False if data.lower().startswith('json '): self.isJSON = True data = data[5:] try: if self.parse_cmd(self.parse(data)) == False: self.output['status'] = 1 self.output['message'].write(">>> Command not recognised. Use 'help' for details" + '\r\n') except Exception: self.output['message'] = StringIO() self.output['message'].write('Unexpected Error\r\nReport to QRL Developers') self.output['message'] = self.output['message'].getvalue() try: if self.isJSON: self.transport.write(json.dumps(self.output)) else: self.transport.write(self.output['message']) except Exception: logger.info(( 'Walletprotocol unexpected exception while sending msg to client')) pass del self.output self.output = {} self.output['status'] = 1 self.output['keys'] = [] self.output['message'] = StringIO()
def f_read_wallet(self): addr_list = [] if os.path.isfile(self.wallet_dat_filename) is False: logger.info( 'Creating new wallet file..this could take up to a minute') SEED = None # For AWS test only if os.path.isfile(self.mnemonic_filename): with open(self.mnemonic_filename, 'r') as f: SEED = f.read() SEED = mnemonic_to_seed(SEED.strip()) # addr_list.append(self.getnewaddress(4096, 'XMSS', SEED=SEED)) addr_list.append(self.getnewaddress(8000, 'XMSS', SEED=SEED)) with open(self.wallet_dat_filename, "a" ) as myfile: # add in a new call to create random_otsmss pickle.dump(addr_list, myfile) while True: try: with open(self.wallet_dat_filename, 'r') as myfile: return pickle.load(myfile) except: logger.warning('Wallet.dat corrupted') logger.warning('Trying to recover') if self.recover_wallet(): continue logger.error('Failed to Recover Wallet') sys.exit()
def f_save_wallet(self): logger.info('Syncing wallet file') with open( self.wallet_dat_filename, "w+" ) as myfile: # overwrites wallet..should add some form of backup to this..seed pickle.dump(self.chain.my, myfile) gc.collect() return
def validate_st_in_block(self): for st in self.stake: if st.validate_tx() is False: logger.info(('invalid st:', st, 'in block')) return False return True
def validate_tx_in_block(self): for transaction in self.transactions: if transaction.validate_tx() is False: logger.info(('invalid tx: ', transaction, 'in block')) return False return True
def get_ntp_response(): try: ntp_client = ntplib.NTPClient() response = ntp_client.request(ntp_server, version=version) except Exception as ex: logger.info(' Failed to Get NTP timing ') logger.info((' Reason - ', str(ex))) sys.exit(0) return response
def ping(self, data=None): logger.info('<<< API network latency ping call') self.factory.pos.p2pFactory.ping_peers( ) # triggers ping for all connected peers at timestamp now. after pong response list is collated. previous list is delivered. pings = {} pings['status'] = 'ok' pings['peers'] = {} pings['peers'] = self.factory.chain.ping_list return helper.json_print_telnet(pings)
def state_validate_tx_pool(self, chain): result = True for tx in chain.transaction_pool: if tx.state_validate_tx(state=self) is False: result = False logger.info(('tx', tx.txhash, 'failed..')) chain.remove_tx_from_pool(tx) return result
def SIGN(self, msg): i = self.index logger.info( ('xmss signing with OTS n = ', str(self.index)) ) # formal sign and increment the index to the next OTS to be used.. s = self.sign(msg, i) auth_route, i_bms = xmss_route(self.x_bms, self.tree, i) self.index += 1 self.remaining -= 1 return i, s, auth_route, i_bms, self.pk(i), self.PK_short
def xmss_route(x_bms, x_tree, i=0): auth_route = [] i_bms = [] nodehash_list = [item for sublist in x_tree for item in sublist] h = len(x_tree) leaf = x_tree[0][i] for x in range(h): if len(x_tree[x]) == 1: # must be at root layer if node == ''.join(x_tree[x]): auth_route.append(''.join(x_tree[x])) else: logger.info('Failed..root') return elif i == len(x_tree[x]) - 1 and leaf in x_tree[ x + 1]: # for an odd node it goes up a level each time until it branches.. i = x_tree[x + 1].index(leaf) n = nodehash_list.index(leaf) nodehash_list[ n] = None # stops at first duplicate in list..need next so wipe.. else: n = nodehash_list.index(leaf) # position in the list == bitmask.. if i % 2 == 0: # left leaf, go right.. # logger.info(( 'left' node = sha256( hex(int(leaf, 16) ^ int(x_bms[n], 16))[2:-1] + hex(int(nodehash_list[n + 1], 16) ^ int(x_bms[n + 1], 16))[2:-1]) pair = nodehash_list[n + 1] auth_route.append(pair) i_bms.append(('L', n, n + 1)) elif i % 2 == 1: # right leaf go left.. node = sha256( hex(int(nodehash_list[n - 1], 16) ^ int(x_bms[n - 1], 16))[2:-1] + hex(int(leaf, 16) ^ int(x_bms[n], 16))[2:-1]) pair = nodehash_list[n - 1] auth_route.append(pair) i_bms.append((n - 1, n)) try: x_tree[x + 1].index( node) # confirm node matches a hash in next layer up? except: logger.info(('Failed at height', str(x))) return leaf = node i = x_tree[x + 1].index(leaf) return auth_route, i_bms
def f_append_wallet(self, data, ignore_chain=False): if not ignore_chain: if not self.chain.my: self.chain.my = self.f_read_wallet() if data is not False: self.chain.my.append(data) logger.info('Appending wallet file..') with open(self.wallet_filename, "w+") as myfile: # overwrites wallet.. pickle.dump(self.chain.my, myfile) self.f_save_winfo() return
def calc_seed(self, sl, verbose=False): if verbose: logger.info(('stake_list --> ')) for s in sl: logger.info((s[0], s[3])) epoch_seed = 0 for staker in sl: epoch_seed |= int(str(staker[3]), 16) return epoch_seed
def unfork(blocknumber, chain): sl = chain.stake_list_get() for blocknum in xrange(blocknumber, chain.height() + 1): stake_selector = chain.m_blockchain[ blocknum].blockheader.stake_selector for s in sl: if stake_selector == s[0]: s[2] -= 1 del chain.m_blockchain[blocknumber:] chain.stake_list_put(sl) logger.info( ('Forked chain has been removed from blocknumber ', blocknumber)) chain.state.update('unsynced')
def GEN( SEED, i, l=32 ): # generates l: 256 bit PRF hexadecimal string at position i. Takes >= 48 byte SEED.. # FIXME: There is no check for the seed size if i < 1: logger.info('i must be integer greater than 0') return z = HMAC_DRBG(SEED) for x in range(i): y = z.generate(l) return y
def seed_to_mnemonic(SEED): if len(SEED) != 48: logger.info('ERROR: SEED is not 48 bytes in length..') return False words = [] y = 0 for x in range(16): three_bytes = format(ord(SEED[y]), '08b') + format( ord(SEED[y + 1]), '08b') + format(ord(SEED[y + 2]), '08b') words.append(wordlist[int(three_bytes[:12], 2)]) words.append(wordlist[int(three_bytes[12:], 2)]) y += 3 return ' '.join(words)
def log_traceback(exctype, value, tb): # Function to log error's traceback logger.info('*** Error ***') logger.info(str(exctype)) logger.info(str(value)) tb_info = extract_tb(tb) for line in tb_info: logger.info(tb_info)
def __init__(self): self.db_path = os.path.join(config.user.data_path, config.dev.db_name) logger.info('DB path: %s', self.db_path) try: # TODO: This is easier in python3 with exists_ok=True os.makedirs(self.db_path) except OSError as err: if err.errno != 17: # Already exists raise # TODO: leveldb python module is not very active. Decouple and replace self.destroy() self.db = leveldb.LevelDB(self.db_path)
def address_adds(self, start_i, stop_i): # batch creation of multiple addresses.. if start_i > self.signatures or stop_i > self.signatures: logger.info( 'ERROR: i cannot be greater than pre-calculated signature count for xmss tree' ) return False if start_i >= stop_i: logger.info('ERROR: starting i must be lower than stop_i') return False for i in range(start_i, stop_i): self.address_add(i) return
def f_save_winfo(self): data = [] for tree in self.chain.my: if type(tree[1]) == list: pass else: if tree[1].type == 'XMSS': data.append([ tree[1].mnemonic, tree[1].hexSEED, tree[1].signatures, tree[1].index, tree[1].remaining ]) logger.info('Fast saving wallet recovery details to wallet.info..') # stores the recovery phrase, signatures and the index for each tree in the wallet.. with open(self.wallet_info_filename, "w+") as myfile: pickle.dump(data, myfile) return
def __init__(self, signatures, index=0, verbose=0): self.signatures = signatures self.merkle_obj = [] self.merkle_root = '' self.merkle_path = [] self.state = 0 self.type = 'WOTS' self.index = index self.concatpub = "" if verbose == 1: logger.info(('New W-OTS keypair generation ', str(self.index))) self.priv, self.pub = random_wkey(verbose=verbose) self.concatpub = ''.join(self.pub) self.pubhash = sha256(self.concatpub) return
def GEN_range( SEED, start_i, end_i, l=32 ): # returns start -> end iteration of hex PRF (inclusive at both ends) if start_i < 1: logger.info('starting i must be integer greater than 0') return z = HMAC_DRBG(SEED) random_arr = [] for x in range(1, end_i + 1): y = hexlify(z.generate(l)) if x >= start_i: random_arr.append(y) return random_arr
def mnemonic_to_seed( mnemonic ): # takes a string..could use type or isinstance here..must be space not comma delimited.. words = mnemonic.lower().split() if len(words) != 32: logger.info('ERROR: mnemonic is not 32 words in length..') return False SEED = '' y = 0 for x in range(16): n = format(wordlist.index(words[y]), '012b') + format( wordlist.index(words[y + 1]), '012b') SEED += chr(int(n[:8], 2)) + chr(int(n[8:16], 2)) + chr(int(n[16:], 2)) y += 2 return SEED
def GEN_range_bin( SEED, start_i, end_i, l=32 ): # returns start -> end iteration of bin PRF (inclusive at both ends) # FIXME: code repetition if start_i < 1: logger.info('starting i must be integer greater than 0') return z = HMAC_DRBG(SEED) random_arr = [] for x in range(1, end_i + 1): y = z.generate(l) if x >= start_i: random_arr.append(y) return random_arr
def __init__(self, signatures, index=0, verbose=0): self.signatures = signatures self.merkle_obj = [] self.merkle_root = '' self.merkle_path = [] self.state = 0 self.type = 'LDOTS' self.index = index self.concatpub = "" if verbose == 1: logger.info(('New LD keypair generation ', str(self.index))) self.priv, self.pub = random_lkey() self.publist = [i for sub in self.pub for i in sub ] # convert list of tuples to list to allow cat. self.concatpub = ''.join(self.publist) self.pubhash = sha256(self.concatpub) return
def random_wkey(w=8, verbose=0): # create random W-OTS keypair # Use F = SHA256/SHA512 and G = SHA256/512 if w > 16: w = 16 # too many hash computations to make this sensible. 16 = 3.75s, 8 = 0.01s 1024 bytes.. priv = [] pub = [] start_time = time.time() for x in range(256 / w): a = random_key() priv.append(a) for y in range(2**w - 1): # F a = sha256(a) pub.append(sha256(a)) # G (just in case we have a different f from g). elapsed_time = time.time() - start_time if verbose == 1: logger.info((elapsed_time)) return priv, pub
def address_add( self, i=None ): # derive new address from an xmss tree using the same SEED but i base leaves..allows deterministic address creation if i == None: i = self.signatures - len(self.addresses) if i > self.signatures or i < self.index: logger.info( 'ERROR: i cannot be below signing index or above the pre-calculated signature count for xmss tree' ) return False xmss_array, x_bms, l_bms, privs, pubs = xmss_tree( i, self.private_SEED, self.public_SEED) i_PK = [''.join(xmss_array[-1]), hexlify(self.public_SEED)] new_addr = 'Q' + sha256(''.join(i_PK)) + sha256(sha256( ''.join(i_PK)))[:4] self.addresses.append((len(self.addresses), new_addr, i)) self.subtrees.append((len(self.subtrees), i, xmss_array, x_bms, i_PK)) # x_bms could be limited to the length.. return new_addr
def random_wpkey(w=16, verbose=0): if verbose == 1: start_time = time.time() # first calculate l_1 + l_2 = l .. see whitepaper http://theqrl.org/whitepaper/QRL_whitepaper.pdf # if using SHA-256 then m and n = 256 if w == 16: l = 67 l_1 = 64 l_2 = 3 else: m = 256 l_1 = ceil(m / log(w, 2)) l_2 = floor(log((l_1 * (w - 1)), 2) / log(w, 2)) + 1 l = int(l_1 + l_2) sk = [] pub = [] # next create l+w-1 256 bit secret key fragments..(we will update this to use a PRF instead of random_key) # l n-bits will be private key, remaining w-1 will be r, the randomisation elements for the chaining function # finally generate k the key for the chaining function.. for x in range(l + w - 1): sk.append(random_key()) priv = sk[:-(w - 1)] r = sk[l:] k = random_key() pub.append( (r, k)) # pk_0 = (r,k) ..where r is a list of w-1 randomisation elements for sk_ in priv: pub.append(chain_fn(sk_, r, w - 1, k)) if verbose == 1: logger.info((str(time.time() - start_time))) return priv, pub
def random_ldmss(signatures=4, verbose=0): begin = time.time() data = [] pubhashes = [] for x in range(signatures): data.append(LDOTS(signatures, index=x, verbose=verbose)) for i in range(len(data)): pubhashes.append(data[i].pubhash) a = Merkle(base=pubhashes, verbose=verbose) for y in range(signatures): data[y].merkle_root = ''.join(a.root) data[y].merkle_path = a.auth_lists[y] data[y].merkle_obj = a if verbose == 1: logger.info(('Total MSS time = ', str(time.time() - begin))) return data
def recover_wallet(self): try: with open(self.wallet_info_filename, 'r') as myfile: data = pickle.load(myfile) if data and len(data[0]) != 5: logger.info('wallet.info is also corrupted, cannot recover') return False except: logger.error('Wallet.info is corrupted') return False with open(self.wallet_dat_filename, "w+") as myfile: pass self.chain.my = [] for wallets in data: words = wallets[0] addr = self.getnewaddress(type='XMSS', SEED=mnemonic_to_seed(words)) self.f_append_wallet(addr, True) return True