def create_transaction(self, required_data): change_address = required_data['transaction'].get('change_address') if change_address: blinding_pubkey = elements.get_blinding_pubkey( self.client, h2b(change_address['btc']['blinding_script_hash'])) return json.dumps( {'blinding_keys': { 'btc': blinding_pubkey.hex() }}) else: return json.dumps({'blinding_keys': {}})
def get_balance(self, required_data): nonces = [ elements.get_rangeproof_nonce(self.client, ecdh_pubkey=h2b(script['pubkey']), script_pubkey=h2b(script['script'])) for script in required_data['blinded_scripts'] ] assert len(nonces) return json.dumps({'nonces': [nonce.hex() for nonce in nonces]})
def sign_message(self, required_data): sig = btc.sign_message(self.client, "Bitcoin", required_data['path'], required_data['message']) # TODO: trezor appears to generate a recoverable sig sig_der = wally.ec_sig_to_der(sig['signature'][1:]) return json.dumps({ 'signature': sig_der.hex(), 'signature_b64': base64.b64encode(sig['signature']).decode('ascii') })
def sign_tx(self, required_data): signing_inputs = required_data['signing_inputs'] transaction_outputs = required_data['transaction_outputs'] signing_transactions = required_data['signing_transactions'] signing_address_types = required_data['signing_address_types'] scripts = [] for in_ in signing_inputs: service_xpub = deserialize(in_['service_xpub']) user_xpub = deserialize(self.as_xpub(in_['user_path'][:-1])) pointer = in_['pointer'] redeem_script = proto.MultisigRedeemScriptType( nodes=[user_xpub, service_xpub], address_n=[pointer], signatures=[b'', b''], m=2, csv=in_['subtype']) scripts.append(redeem_script) ins = [] for i, txin in enumerate(signing_inputs): in_ = proto.TxInputType( address_n=txin['user_path'], prev_hash=h2b(txin['txhash']), prev_index=txin['pt_idx'], script_type=proto.InputScriptType.SPENDP2SHWITNESS, multisig=scripts[i], amount=txin['satoshi'], sequence=txin['sequence']) in_.confidential = proto.TxConfidentialAsset( asset=h2b(txin['asset_id'])[::-1], amount_blind=h2b(txin['vbf']), asset_blind=h2b(txin['abf'])) ins.append(in_) values = [] in_vbfs = [] in_abfs = [] for txin in signing_inputs: in_vbfs.append(h2b(txin['vbf'])) in_abfs.append(h2b(txin['abf'])) values.append(txin['satoshi']) out_vbfs = [] out_abfs = [] for i, txout in enumerate(transaction_outputs): if txout['is_fee']: continue out_vbfs.append( os.urandom(32)) # TODO: check if HW is going to generate these out_abfs.append( os.urandom(32)) # TODO: check if HW is going to generate these values.append(txout['satoshi']) abfs = in_abfs + out_abfs vbfs = in_vbfs + out_vbfs[:-1] final_vbf = wally.asset_final_vbf(values, len(signing_inputs), b''.join(abfs), b''.join(vbfs)) out_vbfs[-1] = final_vbf outs = [] for i, txout in enumerate(transaction_outputs): if txout['is_fee']: out = proto.TxOutputType(address='', amount=txout['satoshi']) out.confidential = proto.TxConfidentialAsset( asset=h2b(txout['asset_id'])[::-1]) else: out = proto.TxOutputType( address=txout['address'], amount=txout['satoshi'], script_type=proto.OutputScriptType.PAYTOADDRESS) out.confidential = proto.TxConfidentialAsset( asset=h2b(txout['asset_id'])[::-1], amount_blind=out_vbfs[i], asset_blind=out_abfs[i], nonce_privkey=h2b(txout['eph_keypair_sec'])) outs.append(out) signatures, serialized_tx = btc.sign_tx( self.client, 'Elements', ins, outs, prev_txes=None, details=proto.SignTx(version=2, lock_time=required_data['transaction'] ['transaction_locktime'])) # with open('tx.txt', 'w') as f: # f.write(serialized_tx.hex()) asset_commitments = [] value_commitments = [] tx = wally.tx_from_bytes( serialized_tx, wally.WALLY_TX_FLAG_USE_WITNESS | wally.WALLY_TX_FLAG_USE_ELEMENTS) for i in range(wally.tx_get_num_outputs(tx)): asset_commitments.append(wally.tx_get_output_asset(tx, i)) value_commitments.append(wally.tx_get_output_value(tx, i)) out_abfs.append(b'\x00' * 32) # FIXME: GDK enforcing blinding factors for fee out_vbfs.append(b'\x00' * 32) return json.dumps({ 'signatures': [sig.hex() + '01' for sig in signatures], 'vbfs': [vbf.hex() for vbf in out_vbfs], 'abfs': [abf.hex() for abf in out_abfs], 'asset_commitments': [commitment.hex() for commitment in asset_commitments], 'value_commitments': [commitment.hex() for commitment in value_commitments] })
def get_receive_address(self, required_data): blinding_pubkey = elements.get_blinding_pubkey( self.client, h2b(required_data['address']['blinding_script_hash'])) return json.dumps({'blinding_key': blinding_pubkey.hex()})
def get_xpubs(self, required_data): return json.dumps({ 'xpubs': self.__get_xpubs_from_path_array(required_data['paths']) })