Skip to content

Files

Latest commit

 

History

History

express

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Jan 23, 2025
Jan 24, 2025
Jan 18, 2025
Jan 22, 2025
Jan 23, 2025
Jan 18, 2025

E2EE with XMTP Handshake

Warning

This is a proof of concept and is not officially supported by XMTP protocol.

XMTP assists in verifying identities and establishing the initial handshake to share the shared secret. Afterward, you manage end-to-end encryption independently, ensuring complete privacy by never exposing plaintext messages outside your environment.

  1. Use XMTP network only once to exchange a shared secret. You only need to know the sender/reciever xmtp address (evm).
  2. Encrypt messages locally with @xmtp/agent-starter.
  3. Send only nonce + ciphertext across your own servers, no plaintext ever leaves your app.
  4. Decrypt: Recive the message using a standard web2 API and decrypt it.

Below is a simple example using Node.js and Express to demonstrate the encryption and decryption process.

Sending encrypted message

Create XMTP client

import { xmtpClient } from "@xmtp/agent-starter";

async function main() {
  const agentA = await xmtpClient({ name: "bob" });
  // ...
}

Agent A encrypts a message intended for Agent B.

setTimeout(async () => {
  const { nonce, ciphertext } = await agentA.encrypt(
    "Hello from A!",
    agentB.address,
  );
  await fetch("http://localhost:3001/receive", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ nonce, ciphertext, fromAddress: agentA.address }),
  });
}, 2000);
  • agentA.encrypt: This function encrypts the plaintext message "Hello from A!" using Agent B's address.
  • nonce: A unique number used once to ensure that the same plaintext will encrypt to different ciphertexts each time.
  • ciphertext: The encrypted version of the message that can be safely sent over the network.

Decrypting message

Create XMTP client

import { xmtpClient } from "@xmtp/agent-starter";

async function main() {
  const agentB = await xmtpClient({ name: "bob" });
  // ...
}

Agent B decrypts the received message.

appB.post("/receive", async (req, res) => {
  const { nonce, ciphertext, fromAddress } = req.body;
  const msg = await agentB.decrypt(nonce, ciphertext, fromAddress);
  console.log("B decrypted:", msg);
  res.json({ success: true });
});
  • agentB.decrypt: This function takes the nonce, ciphertext, and the sender's address (fromAddress) as inputs to decrypt the message.
  • msg: The decrypted plaintext message that was originally sent by Agent A.

Summary

This example demonstrates a simple proof of concept for end-to-end encryption using XMTP. It sets up two agents and two servers, encrypts a message, and sends it securely from one agent to another. The servers handle the decryption of received messages.