docs: def getSharedSecretPassive(
          self,
          passive_exchange_data,
          allow_no_otpk = False,
          keep_otpk = False
      ):
          """
          Do the key exchange, as the passive party. This involves retrieving data about the
          key exchange from the active party.
  
          :param passive_exchange_data: A structure generated by the active party, which
              contains data requried to complete the key exchange. See the "to_other" part
              of the structure returned by "getSharedSecretActive".
          :param allow_no_otpk: A boolean indicating whether to allow key exchange, even if
              the active party did not use a one-time pre key. The recommended default is
              False.
          :param keep_otpk: Keep the one-time pre key after using it, instead of deleting
              it. See the notes below.
          :returns: A dictionary containing the shared secret and the shared associated
              data.
  
          The returned structure looks like this::
          
              {
                  "ad": bytes, # The shared associated data
                  "sk": bytes  # The shared secret
              }
  
          The specification of X3DH dictates to delete one-time pre keys as soon as they are
          used.
  
          This behaviour provides security but may lead to considerable usability downsides
          in some environments.
  
          For that reason the keep_otpk flag exists.
          If set to True, the one-time pre key is not automatically deleted.
          USE WITH CARE, THIS MAY INTRODUCE SECURITY LEAKS IF USED INCORRECTLY.
          If you decide to set the flag and to keep the otpks, you have to manage deleting
          them yourself, e.g. by subclassing this class and overriding this method.
  
          :raises KeyExchangeException: If an error occurs during the key exchange. The
              exception message will contain (human-readable) details.
          """
  
          self.__checkSPKTimestamp()
  
          other_ik = self.__KeyPair(pub = passive_exchange_data["ik"])
          other_ek = self.__KeyPair(pub = passive_exchange_data["ek"])
  
          if self.__spk["key"].pub != passive_exchange_data["spk"]:
              raise KeyExchangeException(
                  "The SPK used for this key exchange has been rotated, the key exchange " +
                  "can not be completed."
              )
  
          my_otpk = None
          if "otpk" in passive_exchange_data:
              for otpk in self.__otpks:
                  if otpk.pub == passive_exchange_data["otpk"]:
                      my_otpk = otpk
                      break
  
              for otpk in self.__hidden_otpks:
                  if otpk.pub == passive_exchange_data["otpk"]:
                      my_otpk = otpk
                      break
  
              if not my_otpk:
                  raise KeyExchangeException(
                      "The OTPK used for this key exchange has been deleted, the key " +
                      "exchange can not be completed."
                  )
          elif not allow_no_otpk:
              raise KeyExchangeException(
                  "This key exchange data does not contain an OTPK, which is not allowed."
              )
  
          dh1 = self.__spk["key"].getSharedSecret(other_ik)
          dh2 = self.__ik.getSharedSecret(other_ek)
          dh3 = self.__spk["key"].getSharedSecret(other_ek)
          dh4 = b""
          
          if my_otpk:
              dh4 = my_otpk.getSharedSecret(other_ek)
  
          sk = self.__kdf(dh1 + dh2 + dh3 + dh4)
  
          other_ik_pub_serialized = self.__PublicKeyEncoder.encodePublicKey(
              other_ik.pub,
              self.__curve
          )
  
          ik_pub_serialized = self.__PublicKeyEncoder.encodePublicKey(
              self.__ik.pub,
              self.__curve
          )
  
          ad = other_ik_pub_serialized + ik_pub_serialized
  
          if my_otpk and not keep_otpk:
              self.deleteOTPK(my_otpk.pub)
  
          return {
              "ad": ad,
              "sk": sk
          }