def from_slip32(master_key: str, root_path=None) -> Xprv: bech = bech32_decode_address(master_key) idx = 0 # byte lengths of the serialized byte data DEPTH = 1 INDEX = 4 * bech[idx:idx + DEPTH][0] CHAIN = 32 secret_prefix = b'\x00' KEYLN = 32 depth = bech[idx:idx + DEPTH] idx += DEPTH index = None chain_code = bytes(bech[idx:idx + CHAIN]) idx += CHAIN idx += len(secret_prefix) key_data = bytes(bech[idx:idx + KEYLN]) private_key = WitPrivateKey(key_data) public_key = private_key.to_public() chain_code = bytes(bech[1:33]) private_key = WitPrivateKey(bytes(bech[34:66])) return Xprv(key=private_key, code=chain_code, depth=depth[0], path=root_path)
def from_xprv(cls, xprv: str) -> 'Xprv': ... from witnet.util.transformations.bech32 import bech32_decode_address bech = bech32_decode_address(xprv) idx = 0 # byte lengths of the serialized byte data DEPTH = 1 INDEX = 4 * bech[idx:idx + DEPTH][0] CHAIN = 32 secret_prefix = b'\x00' KEYLN = 32 depth = bech[idx:idx + DEPTH] idx += DEPTH if INDEX == 0: print('MasterKey') index = None chain_code = bytes(bech[idx:idx + CHAIN]) idx += CHAIN idx += len(secret_prefix) key_data = bytes(bech[idx:idx + KEYLN]) private_key = WitPrivateKey(key_data) public_key = private_key.to_public() chain_code = bytes(bech[1:33]) tmp_xprv = Xprv(key=private_key, code=chain_code, depth=depth[0]) return bech
def child(self, i: int) -> 'Xpub': hardened = i >= 1 << 31 if hardened: raise KeyDerivationError( 'Cannot derive a hardened key from an extended public key') I = hmac.new(key=self.code, msg=self.keydata() + int_to_bytes(i).rjust(4, b'\x00'), digestmod=hashlib.sha512).digest() tmp = bytes_to_hex(self.keydata() + int_to_bytes(i).rjust(4, b'\x00')) I_L, I_R = I[:32], I[32:] key = WitPrivateKey(I_L).to_public().point + self.key.point ret_code = I_R path = self.path + f'/{i}' # TODO add point at infinity check return Xpub(WitPublicKey(key), ret_code, depth=self.depth + 1, i=i, parent=self.fingerprint(), path=path)
def child(self, i: int) -> 'Xprv': hardened = i >= 1 << 31 if hardened: I = hmac.new(key=self.code, msg=self.keydata() + int_to_bytes(i).rjust(4, b'\x00'), digestmod=hashlib.sha512).digest() tmp = int_to_bytes(i).rjust(4, b'\x00') else: I = hmac.new(key=self.code, msg=self.key.to_public().encode(compressed=True) + int_to_bytes(i).rjust(4, b'\x00'), digestmod=hashlib.sha512).digest() tmp = self.key.to_public().encode( compressed=True) + int_to_bytes(i).rjust(4, b'\x00') I_L, I_R = bytes_to_int(I[:32]), I[32:] key = (I_L + self.key.int()) % CURVE.order if I_L >= CURVE.order or key == 0: return self.child(i + 1) ret_code = I_R if hardened: path = self.path + f'/{i - 2 ** 31}h' else: path = self.path + f'/{i}' return Xprv(WitPrivateKey.from_int(key), ret_code, depth=self.depth + 1, i=i, parent=self.fingerprint(), path=path)
def test_sign_and_verify(self): data = hex_to_bytes(concat(['ab' for _ in range(32)])) secret_key = WitPrivateKey.from_hex(concat(['cd' for _ in range(32)])) public_key = secret_key.to_public() local_signature = secret_key.sign_hash(data) expected_signature = '3044' \ '0220' \ '3dc4fa74655c21b7ffc0740e29bfd88647e8dfe2b68c507cf96264e4e7439c1f' \ '0220' \ '7aa61261b18eebdfdb704ca7bab4c7bcf7961ae0ade5309f6f1398e21aec0f9f' recovered_signature = Signature.from_hex(expected_signature) assert local_signature.verify_hash(data, public_key) assert recovered_signature.verify_hash(data, public_key)
def from_seed(cls, seed: Union[bytes, str], network_key=b'Bitcoin seed') -> 'Xprv': """ :param seed: :param network_key: :return: """ if isinstance(seed, str): seed = hex_to_bytes(seed) assert 16 <= len(seed) <= 64, 'Seed should be between 128 and 512 bits' I = hmac.new(key=network_key, msg=seed, digestmod=hashlib.sha512).digest() I_L, I_R = I[:32], I[32:] if bytes_to_int(I_L) == 0 or bytes_to_int(I_L) > CURVE.order: raise KeyDerivationError key, code = WitPrivateKey(I_L), I_R # print(f'\tMaster Secret Key: {bytes_to_hex(I_L)}') # print(f'\tMaster Chain Code: {bytes_to_hex(I_R)}') return cls(key, code)
def deserialize(cls, bts: bytes) -> 'ExtendedKey': from witnet.crypto.hd_wallet.extended_private_key import Xprv from witnet.crypto.hd_wallet.extended_public_key import Xpub def read(n): nonlocal bts data, bts = bts[:n], bts[n:] return data net = read(4) is_private = net in network('Mainnet').values() is_public = net in network('Mainnet').values() assert is_public ^ is_private, f'Invalid network bytes : {bytes_to_hex(net)}' # address_lookup = {val: key for key, val in (network('Mainnet') if is_private else network('Mainnet')).items()} constructor = Xprv if is_private else Xpub depth = bytes_to_int(read(1)) assert depth in range(256), f'Invalid depth : {depth}' fingerprint = read(4) i = bytes_to_int(read(4)) if depth == 0: i = None path = None else: ih = f'{i}' if i < 2**31 else f"{i - 2 ** 31}h" path = '/'.join([constructor.root_path] + ['x' for _ in range(depth - 1)] + [ih]) code = read(32) key = read(33) key = WitPrivateKey(key) if is_private else WitPublicKey.decode(key) assert not bts, 'Leftover bytes' return constructor(key, code, depth=depth, i=i, parent=fingerprint, path=path)
def create_vtt(self, to, private_key: WitPrivateKey, change_address=None, utxo_selection_strategy=None, fee: int = 0, fee_type='absolute'): node = NodeClient.manager() now = datetime.timestamp(datetime.now()) to_sum = 0 print(self.balance) print(to_sum + fee) for receiver in to: to_sum += receiver['value'] to_sum += fee if self.balance < nano_wit_to_wit(to_sum): return '0', {"error": "Insufficient Funds"} available_utxos, selected_utxos = {}, [] for x, utxo in enumerate(self.utxos): if utxo['timelock'] < now: available_utxos[utxo['output_pointer']] = utxo['value'] sorted_x = sorted(available_utxos.items(), key=lambda kv: kv[1]) value_owed = to_sum selected_utxo_total_value = 0 for i, x in enumerate(sorted_x): if value_owed > 0: selected_utxos.append(x) selected_utxo_total_value += x[1] value_owed -= x[1] change = int(abs(value_owed)) if change > 0: to.append({'address': self.address, 'time_lock': 0, 'value': change}) change = 0 inputs, outputs = [], [] # Inputs for utxo in selected_utxos: output_pointer, value = utxo # print(output_pointer, value) _input = Input.from_json({'output_pointer': output_pointer}) inputs.append(_input) # Outputs for receiver in to: pkh = receiver['address'] value = receiver['value'] if 'time_lock' in receiver: time_lock = receiver['time_lock'] else: time_lock = 0 vto_dict = { 'pkh': pkh, 'time_lock': time_lock, 'value': value } output: ValueTransferOutput = ValueTransferOutput.from_json(vto_dict) outputs.append(output) vtt_transaction_body = VTTransactionBody(inputs=inputs, outputs=outputs) vtt_hash = vtt_transaction_body.hash() der_bytes = private_key.sign_hash(vtt_hash).encode(compact=False) signatures = [] signature = Signature(secp256k1=Secp256k1Signature(der=der_bytes)) pubkey = private_key.to_public().pub_key() sig = KeyedSignature(signature=signature, public_key=pubkey) for _input in inputs: signatures.append(sig) vtt_transaction_body = VTTransactionBody(inputs=inputs, outputs=outputs) transaction = VTTransaction(body=vtt_transaction_body, signatures=signatures) return vtt_hash, transaction