def check_covert_component(msg, round_pubkey, component_feerate): message_hash = sha256(msg.component) check(len(msg.signature) == 64, "bad message signature") check(schnorr.verify(round_pubkey, msg.signature, message_hash), "bad message signature") cmsg = proto_strict_parse(pb.Component(), msg.component) check(len(cmsg.salt_commitment) == 32, "bad salt commitment") ctype = cmsg.WhichOneof('component') if ctype == 'input': inp = cmsg.input check(len(inp.prev_txid) == 32, "bad txid") check( (len(inp.pubkey) == 33 and inp.pubkey[0] in (2,3)) or (len(inp.pubkey) == 65 and inp.pubkey[0] == 4), "bad pubkey") sort_key = ('i', inp.prev_txid[::-1], inp.prev_index, cmsg.salt_commitment) elif ctype == 'output': out = cmsg.output atype, addr = get_address_from_output_script(out.scriptpubkey) check(atype == TYPE_ADDRESS, "output is not address") check(out.amount >= dust_limit(len(out.scriptpubkey)), "dust output") sort_key = ('o', out.amount, out.scriptpubkey, cmsg.salt_commitment) elif ctype == 'blank': sort_key = ('b', cmsg.salt_commitment) else: raise ValidationError('missing component details') # Note: for each sort type we use salt_commitment as a tie-breaker, just to # make sure that original ordering is forgotten. Of course salt_commitment # doesn't have to be unique, but it's unique for all honest players. return sort_key, component_contrib(cmsg, component_feerate)
def tx_from_components(all_components, session_hash): """ Returns the tx and a list of indices matching inputs with components""" input_indices = [] assert len(session_hash) == 32 if Protocol.FUSE_ID is None: prefix = [] else: assert len(Protocol.FUSE_ID) == 4 prefix = [4, *Protocol.FUSE_ID] inputs = [] outputs = [ (TYPE_SCRIPT, ScriptOutput(bytes([OpCodes.OP_RETURN, *prefix, 32]) + session_hash), 0) ] for i, compser in enumerate(all_components): comp = pb.Component() comp.ParseFromString(compser) ctype = comp.WhichOneof('component') if ctype == 'input': inp = comp.input if len(inp.prev_txid) != 32: raise FusionError("bad component prevout") inputs.append( dict(address=Address.from_P2PKH_hash(hash160(inp.pubkey)), prevout_hash=inp.prev_txid[::-1].hex(), prevout_n=inp.prev_index, num_sig=1, signatures=[None], type='p2pkh', x_pubkeys=[inp.pubkey.hex()], pubkeys=[inp.pubkey.hex()], sequence=0xffffffff, value=inp.amount)) input_indices.append(i) elif ctype == 'output': out = comp.output atype, addr = get_address_from_output_script(out.scriptpubkey) if atype != TYPE_ADDRESS: raise FusionError("bad component address") outputs.append((TYPE_ADDRESS, addr, out.amount)) elif ctype != 'blank': raise FusionError("bad component") tx = Transaction.from_io(inputs, outputs, locktime=0, sign_schnorr=True) tx.version = 1 return tx, input_indices