def _set_out_derivation( state: State, dst_entr: MoneroTransactionDestinationEntry, additional_txkey_priv: Sc25519, ) -> Ge25519: """ Calculates derivation which is then used in the one-time address as `P = H(derivation)*G + B`. For change outputs the derivation equals a*R, because we know the private view key. For others it is either `r*A` for traditional addresses, or `s*C` for subaddresses. Both `r` and `s` are random scalars, `s` is used in the context of subaddresses, but it's basically the same thing. """ from apps.monero.xmr.addresses import addr_eq change_addr = state.change_address() if change_addr and addr_eq(dst_entr.addr, change_addr): # sending change to yourself; derivation = a*R derivation = crypto.generate_key_derivation( state.tx_pub, state.creds.view_key_private) else: # sending to the recipient; derivation = r*A (or s*C in the subaddress scheme) if dst_entr.is_subaddress and state.need_additional_txkeys: deriv_priv = additional_txkey_priv else: deriv_priv = state.tx_priv derivation = crypto.generate_key_derivation( crypto.decodepoint(dst_entr.addr.view_public_key), deriv_priv) return derivation
def generate_tx_spend_and_key_image_and_derivation( creds: AccountCreds, subaddresses: Subaddresses, out_key: Ge25519, tx_public_key: Ge25519, additional_tx_public_key: Ge25519, real_output_index: int, sub_addr_major: int = None, sub_addr_minor: int = None, ) -> Tuple[Sc25519, Ge25519, Ge25519]: """ Generates UTXO spending key and key image and corresponding derivation. Supports subaddresses. Corresponds to generate_key_image_helper() in the Monero codebase. :param creds: :param subaddresses: :param out_key: real output (from input RCT) destination key :param tx_public_key: R, transaction public key :param additional_tx_public_key: Additional Rs, for subaddress destinations :param real_output_index: index of the real output in the RCT :param sub_addr_major: subaddress major index :param sub_addr_minor: subaddress minor index :return: """ recv_derivation = crypto.generate_key_derivation( tx_public_key, creds.view_key_private ) additional_recv_derivation = ( crypto.generate_key_derivation(additional_tx_public_key, creds.view_key_private) if additional_tx_public_key else None ) subaddr_recv_info = is_out_to_account( subaddresses, out_key, recv_derivation, additional_recv_derivation, real_output_index, creds, sub_addr_major, sub_addr_minor, ) if subaddr_recv_info is None: raise XmrNoSuchAddressException("No such addr") xi, ki = generate_tx_spend_and_key_image( creds, out_key, subaddr_recv_info[1], real_output_index, subaddr_recv_info[0] ) return xi, ki, recv_derivation
def _encrypt_payment_id(payment_id, public_key, secret_key): """ Encrypts payment_id hex. Used in the transaction extra. Only recipient is able to decrypt. """ derivation_p = crypto.generate_key_derivation(public_key, secret_key) derivation = bytearray(33) derivation = crypto.encodepoint_into(derivation, derivation_p) derivation[32] = 0x8D # ENCRYPTED_PAYMENT_ID_TAIL hash = crypto.cn_fast_hash(derivation) pm_copy = bytearray(payment_id) return crypto.xor8(pm_copy, hash)
def _encrypt_payment_id(payment_id, public_key, secret_key): """ Encrypts payment_id hex. Used in the transaction extra. Only recipient is able to decrypt. """ derivation_p = crypto.generate_key_derivation(public_key, secret_key) derivation = bytearray(33) derivation = crypto.encodepoint_into(derivation, derivation_p) derivation[32] = 0x8B hash = crypto.cn_fast_hash(derivation) pm_copy = bytearray(payment_id) for i in range(8): pm_copy[i] ^= hash[i] return pm_copy
def test_generate_key_derivation(self): key_pub = crypto.decodepoint( unhexlify( b"7739c95d3298e2f87362dba9e0e0b3980a692ae8e2f16796b0e382098cd6bd83" )) key_priv = crypto.decodeint( unhexlify( b"3482fb9735ef879fcae5ec7721b5d3646e155c4fb58d6cc11c732c9c9b76620a" )) deriv_exp = unhexlify( b"fa188a45a0e4daccc0e6d4f6f6858fd46392104be74183ec0047e7e9f4eaf739" ) self.assertEqual( deriv_exp, crypto.encodepoint( crypto.generate_key_derivation(key_pub, key_priv)), )