Encrypted, ephemeral, private memos on atproto
1import { XWing } from "@noble/post-quantum/hybrid.js";
2import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
3import { randomBytes } from "@noble/hashes/utils.js";
4import { sha3_512 } from "@noble/hashes/sha3.js";
5import type { EncryptedPayload } from "./types.ts";
6
7export function encryptText(
8 publicKey: Uint8Array,
9 text: string,
10): EncryptedPayload {
11 // Create a copy of the public key to prevent mutation by XWing.encapsulate
12 const publicKeyCopy = new Uint8Array(publicKey);
13 const { cipherText, sharedSecret } = XWing.encapsulate(publicKeyCopy);
14 const nonce = randomBytes(24);
15 const contentBytes = new TextEncoder().encode(text);
16 const cipher = xchacha20poly1305(sharedSecret, nonce);
17 const content = cipher.encrypt(contentBytes);
18 const hash = sha3_512(contentBytes);
19
20 return {
21 cipherText: cipherText.toBase64(),
22 content: content.toBase64(),
23 nonce: nonce.toBase64(),
24 hash: hash.toBase64(),
25 length: contentBytes.byteLength,
26 };
27}