Now that we have their public key, we can encrypt our secret message.
Remember our "outside-in" principle: we use THEIR public (outside) key to encrypt the message, which ensures that only THEIR private (inside) key can decrypt it.
The message gets transformed into a scrambled format that is completely unreadable to anyone who might intercept it - only the owner of the matching private key can convert it back to the original text. Each encrypted message is unique, even if you encrypt the same text multiple times, adding an extra layer of security.
import tweetnacl from 'tweetnacl';
import { Buffer } from "buffer";
import { Wallet } from "xrpl";
import {
edwardsToMontgomeryPub,
edwardsToMontgomeryPriv,
} from "@noble/curves/ed25519";
const { box, randomBytes } = tweetnacl;
/**
* Encrypts a message using X25519 (Montgomery curve) for Diffie-Hellman key exchange
*
* @param message - Plain text message to encrypt
* @param recipientPublicKey - Recipient's Ed25519 public key (hex encoded)
* @param senderSecretKey - Sender's Ed25519 private key (hex encoded)
* @returns JSON string containing base64 encoded encrypted message and nonce
*
* Steps:
* 1. Convert hex keys to byte arrays
* 2. Generate random nonce for uniqueness
* 3. Convert message to bytes
* 4. Convert Ed25519 keys to X25519 (Montgomery) format for encryption
* 5. Encrypt using NaCl box with converted keys
* 6. Return encrypted message and nonce as base64 JSON
*/
export function encryptMessage(
message: string,
recipientPublicKey: string,
senderSecretKey: string,
): string {
const pubKeyBytes = Buffer.from(recipientPublicKey.slice(2), "hex");
const secretKeyBytes = Buffer.from(senderSecretKey.slice(2), "hex");
const nonce = randomBytes(box.nonceLength);
const messageUint8 = Buffer.from(message);
const pubKeyCurve = edwardsToMontgomeryPub(pubKeyBytes);
const privKeyCurve = edwardsToMontgomeryPriv(secretKeyBytes);
const encryptedMessage = box(messageUint8, nonce, pubKeyCurve, privKeyCurve);
return JSON.stringify({
encrypted: Buffer.from(encryptedMessage).toString("base64"),
nonce: Buffer.from(nonce).toString("base64"),
});
}
function main() {
const recipientPublicKey ="Recipient pubkey goes here";
const myWallet = Wallet.fromSeed("your seed goes here");
const cypheredMessage = encryptMessage(
"Hello World",
recipientPublicKey,
myWallet.privateKey,
);
console.log(cypheredMessage);
}
main();