docstr: Convert a phe-tensor to MPC encrypted tensor.
  
  phe_tensor_a: a phe-tensor that belongs to rank_a with corresponding phe_cipher_b holding by rank_b.
docstr_tok: ["Convert","a","phe-tensor","to","MPC","encrypted","tensor",".","phe_tensor_a",":","a","phe-tensor","that","belongs","to","rank_a","with","corresponding","phe_cipher_b","holding","by","rank_b","."]
code: def phe_to_mpc(
      cls,
      ctx: Context,
      group,
      rank_a,
      rank_b,
      phe_tensor_a,
      phe_cipher_b,
  ):
      """
      Convert a phe-tensor to MPC encrypted tensor.
  
      phe_tensor_a: a phe-tensor that belongs to rank_a with corresponding phe_cipher_b holding by rank_b.
      """
      ctx.mpc.option_assert(
          lambda: phe_tensor_a is not None,
          "phe_tensor should not be None on src_rank",
          dst=rank_a,
      )
      ctx.mpc.option_assert(
          lambda: phe_cipher_b is None,
          "phe_cipher should be None on src_rank",
          dst=rank_a,
      )
      ctx.mpc.option_assert(
          lambda: phe_tensor_a is None,
          "phe_tensor should be None on dst_rank",
          dst=rank_b,
      )
      ctx.mpc.option_assert(
          lambda: phe_cipher_b is not None,
          "phe_cipher should not be None on dst_rank",
          dst=rank_b,
      )
      assert (
          isinstance(rank_a, int) and 0 <= rank_a < ctx.world_size
      ), f"invalid src_rank: {rank_a}"
      assert (
          isinstance(rank_b, int) and 0 <= rank_b < ctx.world_size
      ), f"invalid dst_rank: {rank_b}"
      src_share = ctx.mpc.option_call(
          lambda: generate_random_ring_element(
              ctx,
              phe_tensor_a.shardings.shapes
              if isinstance(phe_tensor_a, DTensor)
              else phe_tensor_a.shape,
          ),
          dst=rank_a,
      )
      dst_share = ctx.mpc.option_call(
          lambda: phe_tensor_a - src_share, dst=rank_a
      )
      dst_share = ctx.mpc.communicator.broadcast(
          dst_share, src=rank_a, group=group
      )
      dst_share = ctx.mpc.option_call(
          lambda: phe_cipher_b.get_tensor_decryptor().decrypt_tensor(
              dst_share
          ),
          dst=rank_b,
      )
      share = ctx.mpc.cond(src_share, dst_share, dst=rank_a)
      return ArithmeticSharedTensor.from_shares(ctx, share)
  
file_path: FATE/python/fate/arch/protocol/mpc/primitives/sshe.py
imports: import typing
  import torch
  from fate.arch.context import Context
  from fate.arch.tensor import DTensor
  from fate.arch.protocol.mpc.common.rng import generate_random_ring_element
  from fate.arch.protocol.mpc.primitives.arithmetic import ArithmeticSharedTensor
  from fate.arch.protocol.mpc.primitives.beaver import IgnoreEncodings
  from fate.arch.trace import auto_trace
label_desc: Use image node_id 4 for calling the SSHE obj's underlying member method code with example usage: obj.phe_to_mpc(cls, ctx, group, rank_a, rank_b, phe_tensor_a, phe_cipher_b) and returns: ArithmeticSharedTensor