ML-KEM Encryption for Backups
Last updated
{
"signature": "0x...", // 49,856-byte SLH-DSA signature
"payload": "0x..." // ML-KEM ciphertext + symmetrically encrypted data
}const legitMessages = [
`${pubkey}-GET-BACKUPS-${ymdnow}`,
`${pubkey}-GET-BACKUPS-${ymdlb}`, // Lower bound timestamp
`${pubkey}-GET-BACKUPS-${ymdub}`, // Upper bound timestamp
]; const valid = slh.slh_dsa_shake_256f.verify(
pubkeyBytes,
messageBuffer,
signature
); // Verify SLH-DSA signature to prove ownership of ML-KEM key
let provenOwnership = false;
for (const message of legitMessages) {
const valid = slh.slh_dsa_shake_256f.verify(
pubkeyBytes, // SLH-DSA public key (derived from same mnemonic as ML-KEM key)
Buffer.from(message, "utf8"),
byteStringToBytes(signature)
);
if (valid) {
provenOwnership = true;
break;
}
}
if (!provenOwnership) {
throw new HttpError(HttpStatus.BadRequest, ERROR_MESSAGE.INVALID_SIGNATURE);
}const backup = await getBackup(userId);const sharedSecret = ml_kem.decapsulate(ciphertext, privateKey);const decryptedBackup: BackupData = JSON.parse(decryptedData.toString());