docs: def EncodeMessages(self,
                       message_list,
                       result,
                       destination=None,
                       timestamp=None,
                       api_version=3):
      """Accepts a list of messages and encodes for transmission.
  
      This function signs and then encrypts the payload.
  
      Args:
         message_list: A MessageList rdfvalue containing a list of GrrMessages.
         result: A ClientCommunication rdfvalue which will be filled in.
         destination: The CN of the remote system this should go to.
         timestamp: A timestamp to use for the signed messages. If None - use the
           current time.
         api_version: The api version which this should be encoded in.
  
      Returns:
         A nonce (based on time) which is inserted to the encrypted payload. The
         client can verify that the server is able to decrypt the message and
         return the nonce.
  
      Raises:
         RuntimeError: If we do not support this api version.
      """
      if api_version not in [3]:
        raise RuntimeError(
            "Unsupported api version: %s, expected 3." % api_version)
      # TODO(amoser): This is actually not great, we have two
      # communicator classes already, one for the client, one for the
      # server. This should be different methods, not a single one that
      # gets passed a destination (server side) or not (client side).
      if destination is None:
        destination = self.server_name
        # For the client it makes sense to cache the server cipher since
        # it's the only cipher it ever uses.
        cipher = self._GetServerCipher()
      else:
        remote_public_key = self._GetRemotePublicKey(destination)
        cipher = Cipher(self.common_name, self.private_key, remote_public_key)
  
      # Make a nonce for this transaction
      if timestamp is None:
        self.timestamp = timestamp = int(time.time() * 1000000)
  
      packed_message_list = rdf_flows.PackedMessageList(timestamp=timestamp)
      self.EncodeMessageList(message_list, packed_message_list)
  
      result.encrypted_cipher_metadata = cipher.encrypted_cipher_metadata
  
      # Include the encrypted cipher.
      result.encrypted_cipher = cipher.encrypted_cipher
  
      serialized_message_list = packed_message_list.SerializeToString()
  
      # Encrypt the message symmetrically.
      # New scheme cipher is signed plus hmac over message list.
      result.packet_iv, result.encrypted = cipher.Encrypt(serialized_message_list)
  
      # This is to support older endpoints.
      result.hmac = cipher.HMAC(result.encrypted)
  
      # Newer endpoints only look at this HMAC. It is recalculated for each packet
      # in the session. Note that encrypted_cipher and encrypted_cipher_metadata
      # do not change between all packets in this session.
      result.full_hmac = cipher.HMAC(result.encrypted, result.encrypted_cipher,
                                     result.encrypted_cipher_metadata,
                                     result.packet_iv.SerializeToString(),
                                     struct.pack("<I", api_version))
  
      result.api_version = api_version
  
      if isinstance(result, rdfvalue.RDFValue):
        # Store the number of messages contained.
        result.num_messages = len(message_list)
  
      return timestamp