Note: đźš§ Deprecated: refer instead to npm package quantum-resistant-rustykey đźš§
A WebAssembly implementation of ML-KEM (Quantum-Resistant Signatures) for both Node.js and web environments. This is an improved version of the NIST winner's standard implementation, patched to withstand side-channel attacks.
A WASM implementation of "Cryptographic Suite for Algebraic Lattices" (CRYSTALS) based on hard problems over module lattices, designed to withstand attacks by large quantum computers, and selected among the winners of the NIST post-quantum cryptography project
Package | Registry | Description |
---|---|---|
quantum-resistant-rustykey | đźš§ WORK IN PROGRESS đźš§ |
For Node.js, you can install quantum-resistant-rustykey via pnpm, npm or yarn:
pnpm install quantum-resistant-rustykey
# or
npm install quantum-resistant-rustykey
# or
yarn add quantum-resistant-rustykey
import { loadMlKem1024, loadMlKem768, loadMlKem512 } from "quantum-resistant-rustykey";
async function main() {
try {
// Load the desired ML-KEM variant
const mlkem = await loadMlKem1024(); // Options: loadMlKem1024, loadMlKem768, loadMlKem512
// Generate key pair
const keypair = mlkem.keypair();
const publicKey = mlkem.buffer_to_string(keypair.get('public_key'));
const privateKey = mlkem.buffer_to_string(keypair.get('private_key'));
console.log("Public Key:", publicKey);
console.log("Private Key:", privateKey);
// Encrypt a message
const message = "Hello, quantum-resistant world!";
const encrypt = mlkem.encrypt(keypair.get('public_key'));
const ciphertext = mlkem.buffer_to_string(encrypt.get('cyphertext'));
const secret = mlkem.buffer_to_string(encrypt.get('secret'));
console.log("Ciphertext:", ciphertext);
console.log("Secret:", secret);
// Decrypt the message
const decrypted = mlkem.decrypt(encrypt.get('cyphertext'), keypair.get('private_key'));
console.log("Decrypted:", mlkem.buffer_to_string(decrypted));
} catch (error) {
console.error("Error:", error);
}
}
main();
import { loadMlKem1024, loadMlKem768, loadMlKem512 } from 'quantum-resistant-rustykey';
// Example usage in a web application
async function handleEncryption() {
try {
// Load the desired ML-KEM variant
const mlkem = await loadMlKem1024(); // Options: loadMlKem1024, loadMlKem768, loadMlKem512
// Generate key pair
const keypair = mlkem.keypair();
const publicKey = mlkem.buffer_to_string(keypair.get('public_key'));
const privateKey = mlkem.buffer_to_string(keypair.get('private_key'));
// Store keys securely (e.g., in IndexedDB or secure storage)
await storeKeys(publicKey, privateKey);
// Encrypt user data
const userData = {
username: "user123",
email: "[email protected]"
};
const encrypt = mlkem.encrypt(keypair.get('public_key'));
const ciphertext = mlkem.buffer_to_string(encrypt.get('cyphertext'));
const secret = mlkem.buffer_to_string(encrypt.get('secret'));
// Send encrypted data to server
await sendToServer(ciphertext, secret);
} catch (error) {
console.error("Encryption error:", error);
}
}
// Example secure storage implementation
async function storeKeys(publicKey: string, privateKey: string) {
// Implement secure storage (e.g., IndexedDB, Web Crypto API)
// This is just a placeholder - implement proper secure storage
localStorage.setItem('mlkem_publicKey', publicKey);
localStorage.setItem('mlkem_privateKey', privateKey);
}
// Example server communication
async function sendToServer(ciphertext: string, secret: string) {
// Implement server communication
// This is just a placeholder - implement proper API calls
const response = await fetch('/api/secure-data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ciphertext, secret }),
});
return response.json();
}
// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
const encryptButton = document.getElementById('encrypt-button');
if (encryptButton) {
encryptButton.addEventListener('click', handleEncryption);
}
});
When using ML-KEM in a web environment, consider the following security best practices:
-
Key Storage:
- Never store private keys in localStorage or sessionStorage
- Use secure storage mechanisms like IndexedDB with encryption
- Consider using the Web Crypto API for additional security
-
Key Management:
- Generate new key pairs for each session when possible
- Implement proper key rotation policies
- Consider using a key management service for production applications
-
Data Handling:
- Always encrypt sensitive data before transmission
- Use HTTPS for all communications
- Implement proper error handling to prevent information leakage
-
Performance:
- Consider using Web Workers for cryptographic operations
- Implement proper loading states for long-running operations
- Cache public keys when appropriate
- Node.js >= 23.6.0 (optimal)
- Node.js >= 22 (current LTS)
- pnpm (pnpm for faster cache, but npm also works fine)
- Emscripten
- CMake
- Clone the repository:
git clone https://github.com/antonymott/quantum-resistant-rustykey.git
cd quantum-resistant-rustykey
- Initialize submodules:
git submodule update --init --recursive
- Install dependencies:
pnpm i
- Build the WASM engine with Emscripten and CMake
The package supports two different environments:
- Web Environment: Set
sENVIRONMENT=web,worker
in CMakeLists.txt - Node.js Environment: Set
sENVIRONMENT=node,worker
in CMakeLists.txt
pnpm pre
# Copy the WASM file to src directory
cp install/kyber_crystals_wasm_engine.wasm ./src/
The sENVIRONMENT
option specifies which environments the WebAssembly module should be built for:
web
: Enables running in web browsersworker
: Enables running in Web Workersnode
: Enables running in Node.js
For web applications, use web,worker
to support both browser and Web Worker environments.
For Node.js applications, use node,worker
to support both Node.js and Worker Threads.
- Compile TypeScript files to JavaScript
pnpm build
- Tested to work with Node.js v23.6.0
- For web testing, open
install/test.html
in a live server and check the console for encryption/decryption results of the three variants
stateDiagram-v2
[*] --> install
install --> [*]
install --> kyber_crystals_wasm_engine.js
kyber_crystals_wasm_engine.js --> kyber_crystals_wasm_engine.wasm
kyber_crystals_wasm_engine.wasm --> test.html
test.html --> [*]
The package is published from the install
folder. To publish a new version:
- make a new branch locally from main
- edit and test your changes
- pnpm changeset
- build (will run CI/CD tests)
- if it works, CI/CD will generate a pull request for admin to approve
This implementation includes patches to withstand side-channel attacks. For more information about the security improvements, see: RaspberryPi recovers secret keys from NIST winner implementation...within minutes
- Please make pull requests tested to work on Bun and previous Node.js versions
- Follow the existing code style and testing practices
- Include tests for new features
- Update documentation as needed
ISC
- Based on the NIST post-quantum cryptography project
- Inspired by the implementation approach of sqlite-wasm