Exemplo n.º 1
0
def derive_subaddress_public_key(out_key, derivation, output_index):
    """
    out_key - H_s(derivation || varint(output_index))G
    """
    crypto.check_ed25519point(out_key)
    scalar = crypto.derivation_to_scalar(derivation, output_index)
    point2 = crypto.scalarmult_base(scalar)
    point4 = crypto.point_sub(out_key, point2)
    return point4
Exemplo n.º 2
0
 def test_derivation_to_scalar(self):
     derivation = unhexlify(
         b"e720a09f2e3a0bbf4e4ba7ad93653bb296885510121f806acb2a5f9168fafa01"
     )
     scalar = unhexlify(
         b"25d08763414c379aa9cf989cdcb3cadd36bd5193b500107d6bf5f921f18e470e"
     )
     sc_int = crypto.derivation_to_scalar(crypto.decodepoint(derivation), 0)
     self.assertEqual(scalar, crypto.encodeint(sc_int))
Exemplo n.º 3
0
def ecdh_decode_rv(rv, derivation, i):
    """
    Decodes ECDH info from transaction.
    """
    scalar = crypto.derivation_to_scalar(derivation, i)
    if rv.type in [
            xmrtypes.RctType.Simple, xmrtypes.RctType.SimpleBulletproof
    ]:
        return ecdh_decode_simple(rv, scalar, i)

    elif rv.type in [xmrtypes.RctType.Full, xmrtypes.RctType.FullBulletproof]:
        return ecdh_decode_simple(rv, scalar, i)

    else:
        raise ValueError("Unknown rv type")
Exemplo n.º 4
0
    async def set_out1(self, dst_entr):
        """
        Set destination entry
        :param src_entr
        :type src_entr: xmrtypes.TxDestinationEntry
        :return:
        """
        self.out_idx += 1
        change_addr = (
            self.tsx_data.change_dts.addr if self.tsx_data.change_dts else None
        )

        if dst_entr.amount <= 0 and self.tx.version <= 1:
            raise ValueError("Destination with wrong amount: %s" % dst_entr.amount)

        if self.need_additional_txkeys:
            if dst_entr.is_subaddress:
                additional_txkey = crypto.ge_scalarmult(
                    self.additional_tx_keys[self.out_idx],
                    crypto.decodepoint(dst_entr.addr.m_spend_public_key),
                )
            else:
                additional_txkey = crypto.ge_scalarmult_base(
                    self.additional_tx_keys[self.out_idx]
                )

            self.additional_tx_public_keys.append(additional_txkey)

        if change_addr and dst_entr.addr == change_addr:
            # sending change to yourself; derivation = a*R
            derivation = monero.generate_key_derivation(
                self.r_pub, self.creds.view_key_private
            )

        else:
            # sending to the recipient; derivation = r*A (or s*C in the subaddress scheme)
            deriv_priv = (
                self.additional_tx_keys[self.out_idx]
                if dst_entr.is_subaddress and self.need_additional_txkeys
                else self.r
            )
            derivation = monero.generate_key_derivation(
                crypto.decodepoint(dst_entr.addr.m_view_public_key), deriv_priv
            )

        amount_key = crypto.derivation_to_scalar(derivation, self.out_idx)
        tx_out_key = crypto.derive_public_key(
            derivation,
            self.out_idx,
            crypto.decodepoint(dst_entr.addr.m_spend_public_key),
        )
        tk = xmrtypes.TxoutToKey(key=crypto.encodepoint(tx_out_key))
        tx_out = xmrtypes.TxOut(amount=dst_entr.amount, target=tk)
        self.tx.vout.append(tx_out)
        self.summary_outs_money += dst_entr.amount

        self.output_secrets.append((amount_key,))

        # Last output?
        if self.out_idx + 1 == len(self.tsx_data.outputs):
            await self.all_out1_set()
Exemplo n.º 5
0
    async def set_out1(self, dst_entr, dst_entr_hmac):
        """
        Set destination entry one by one.
        Computes destination stealth address, amount key, range proof + HMAC, out_pk, ecdh_info.

        :param dst_entr
        :type dst_entr: TxDestinationEntry
        :param dst_entr_hmac
        :return:
        """
        from monero_serialize import xmrserialize

        await self.trezor.iface.transaction_step(
            self.STEP_OUT, self.out_idx + 1, self.num_dests()
        )
        self._log_trace(1)

        if self.state.is_input_vins() and self.inp_idx + 1 != self.num_inputs():
            raise ValueError("Invalid number of inputs")

        self.state.set_output()
        self.out_idx += 1
        self._log_trace(2)

        if dst_entr.amount <= 0 and self.tx.version <= 1:
            raise ValueError("Destination with wrong amount: %s" % dst_entr.amount)

        # HMAC check of the destination
        dst_entr_hmac_computed = await self.gen_hmac_tsxdest(dst_entr, self.out_idx)
        if not common.ct_equal(dst_entr_hmac, dst_entr_hmac_computed):
            raise ValueError("HMAC invalid")
        gc.collect()
        self._log_trace(3)

        # First output - tx prefix hasher - size of the container
        self.tx_prefix_hasher.refresh(xser=xmrserialize)
        if self.out_idx == 0:
            await self._set_out1_prefix()
        gc.collect()

        self._log_trace(4)
        additional_txkey_priv = await self._set_out1_additional_keys(dst_entr)
        derivation = await self._set_out1_derivation(dst_entr, additional_txkey_priv)

        gc.collect()
        self._log_trace(5)

        amount_key = crypto.derivation_to_scalar(derivation, self.out_idx)
        tx_out_key = crypto.derive_public_key(
            derivation,
            self.out_idx,
            crypto.decodepoint(dst_entr.addr.m_spend_public_key),
        )

        from monero_serialize.xmrtypes import TxoutToKey
        from monero_serialize.xmrtypes import TxOut

        tk = TxoutToKey(key=crypto.encodepoint(tx_out_key))
        tx_out = TxOut(amount=0, target=tk)
        self.summary_outs_money += dst_entr.amount
        self._log_trace(6)

        # Tx header prefix hashing
        await self.tx_prefix_hasher.ar.field(tx_out, TxOut)
        gc.collect()

        # Hmac dest_entr.
        hmac_vouti = await self.gen_hmac_vouti(dst_entr, tx_out, self.out_idx)
        gc.collect()
        self._log_trace(7)

        # Range proof, out_pk, ecdh_info
        rsig, out_pk, ecdh_info = await self.range_proof(
            self.out_idx,
            dest_pub_key=tk.key,
            amount=dst_entr.amount,
            amount_key=amount_key,
        )
        gc.collect()
        self._log_trace(8)

        # Incremental hashing of the ECDH info.
        # RctSigBase allows to hash only one of the (ecdh, out_pk) as they are serialized
        # as whole vectors. Hashing ECDH info saves state space.
        await self.full_message_hasher.set_ecdh(ecdh_info)
        self._log_trace(9)

        # Output_pk is stored to the state as it is used during the signature and hashed to the
        # RctSigBase later.
        self.output_pk.append(out_pk)
        gc.collect()

        self._log_trace(10)
        from monero_glue.messages.MoneroTransactionSetOutputAck import (
            MoneroTransactionSetOutputAck
        )
        from monero_serialize.xmrtypes import CtKey

        return MoneroTransactionSetOutputAck(
            tx_out=await misc.dump_msg(tx_out, preallocate=34),
            vouti_hmac=hmac_vouti,
            rsig=rsig,  # rsig is already byte-encoded
            out_pk=await misc.dump_msg(out_pk, preallocate=64, msg_type=CtKey),
            ecdh_info=await misc.dump_msg(ecdh_info, preallocate=64),
        )
Exemplo n.º 6
0
 async def derivation_to_scalar(self):
     der = crypto.decodepoint(self._fetch_decrypt())
     output_index = self._fetch_u32()
     res = crypto.derivation_to_scalar(der, output_index)
     self._insert_encrypt(crypto.encodeint(res))
     return SW_OK
Exemplo n.º 7
0
 def test_derivation_to_scalar(self):
     derivation = bytes(
         [
             0xe7,
             0x20,
             0xa0,
             0x9f,
             0x2e,
             0x3a,
             0x0b,
             0xbf,
             0x4e,
             0x4b,
             0xa7,
             0xad,
             0x93,
             0x65,
             0x3b,
             0xb2,
             0x96,
             0x88,
             0x55,
             0x10,
             0x12,
             0x1f,
             0x80,
             0x6a,
             0xcb,
             0x2a,
             0x5f,
             0x91,
             0x68,
             0xfa,
             0xfa,
             0x01,
         ]
     )
     scalar = bytes(
         [
             0x25,
             0xd0,
             0x87,
             0x63,
             0x41,
             0x4c,
             0x37,
             0x9a,
             0xa9,
             0xcf,
             0x98,
             0x9c,
             0xdc,
             0xb3,
             0xca,
             0xdd,
             0x36,
             0xbd,
             0x51,
             0x93,
             0xb5,
             0x00,
             0x10,
             0x7d,
             0x6b,
             0xf5,
             0xf9,
             0x21,
             0xf1,
             0x8e,
             0x47,
             0x0e,
         ]
     )
     sc_int = crypto.derivation_to_scalar(crypto.decodepoint(derivation), 0)
     self.assertEqual(scalar, crypto.encodeint(sc_int))