quantum-resistant-rustykey 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -130
- package/dist/index.mjs +2404 -0
- package/package.json +16 -8
- package/dist/index.js +0 -2891
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,80 +1,69 @@
|
|
|
1
|
-
**Note**: 🚧 WORK IN PROGRESS...do not pnpm install 🚧
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
# Quantum-Resistant RustyKey®
|
|
5
2
|
|
|
6
|
-
A WebAssembly implementation of ML-KEM
|
|
3
|
+
A WebAssembly implementation of ML-KEM for both Node.js and web environments.
|
|
7
4
|
|
|
8
5
|
## Implementation status
|
|
9
6
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
7
|
+
- **ML-KEM-512**, **ML-KEM-768**, and **ML-KEM-1024** all use the same stack: [mlkem-native](https://github.com/pq-code-package/mlkem-native) (C) built with **Emscripten**, plus TypeScript adapted from Dmitry Chestnykh’s [mlkem-wasm](https://github.com/dchest/mlkem-wasm), vendored in this repo (no runtime npm dependency on `mlkem-wasm`).
|
|
8
|
+
- **PQClean** and **libsodium** are no longer part of this package’s build or runtime path.
|
|
9
|
+
|
|
10
|
+
## Security assurance and verification
|
|
11
|
+
|
|
12
|
+
This project relies on upstream `mlkem-native` for arithmetic/security properties.
|
|
13
|
+
The three parameter sets (512/768/1024) use the same implementation family and differ only by compile-time parameter selection.
|
|
14
|
+
|
|
15
|
+
### Upstream evidence
|
|
16
|
+
|
|
17
|
+
- `mlkem-native` security/formal-verification statements:
|
|
18
|
+
- [README.md](https://github.com/pq-code-package/mlkem-native/blob/main/README.md)
|
|
19
|
+
- [SOUNDNESS.md](https://github.com/pq-code-package/mlkem-native/blob/main/SOUNDNESS.md)
|
|
20
|
+
- [proofs/hol_light/README.md](https://github.com/pq-code-package/mlkem-native/blob/main/proofs/hol_light/README.md)
|
|
21
|
+
- [proofs/cbmc/README.md](https://github.com/pq-code-package/mlkem-native/blob/main/proofs/cbmc/README.md)
|
|
22
|
+
- Arithmetic implementation details in upstream source:
|
|
23
|
+
- Montgomery multiplication path in `mlk_fqmul()`:
|
|
24
|
+
- [mlkem/src/poly.c](https://github.com/pq-code-package/mlkem-native/blob/main/mlkem/src/poly.c)
|
|
25
|
+
- Barrett reduction path in `mlk_barrett_reduce()`:
|
|
26
|
+
- [mlkem/src/poly.c](https://github.com/pq-code-package/mlkem-native/blob/main/mlkem/src/poly.c)
|
|
27
|
+
- Generic Montgomery reduction helper:
|
|
28
|
+
- [mlkem/src/poly.h](https://github.com/pq-code-package/mlkem-native/blob/main/mlkem/src/poly.h)
|
|
29
|
+
|
|
30
|
+
### What this means for 512/768/1024
|
|
31
|
+
|
|
32
|
+
- Constant-time claims and proofs are provided upstream by `mlkem-native` (see links above).
|
|
33
|
+
- This package builds the same source for all three variants by changing only `MLK_CONFIG_PARAMETER_SET` in `wasm/Makefile`.
|
|
34
|
+
- Variant sizes/parameters are defined upstream in `mlkem/mlkem_native.h`.
|
|
35
|
+
|
|
36
|
+
### How users can independently verify
|
|
37
|
+
|
|
38
|
+
From the repository root:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# 1) Confirm the three variant builds only change parameter set.
|
|
42
|
+
rg "MLK_CONFIG_PARAMETER_SET=512|MLK_CONFIG_PARAMETER_SET=768|MLK_CONFIG_PARAMETER_SET=1024" wasm/Makefile
|
|
43
|
+
|
|
44
|
+
# 2) Confirm Montgomery and Barrett reduction functions exist in upstream source.
|
|
45
|
+
rg "mlk_fqmul|Montgomery multiplication|mlk_barrett_reduce|Barrett reduction" vendor/mlkem-native/mlkem/src/poly.c
|
|
46
|
+
rg "mlk_montgomery_reduce" vendor/mlkem-native/mlkem/src/poly.h
|
|
47
|
+
|
|
48
|
+
# 3) Confirm upstream constant-time/security documentation is present.
|
|
49
|
+
rg "constant-time|secret-dependent|HOL-Light|CBMC" vendor/mlkem-native/README.md vendor/mlkem-native/SOUNDNESS.md
|
|
50
|
+
|
|
51
|
+
# 4) (Optional) Rebuild the vendored wasm/modules from source.
|
|
52
|
+
pnpm build:vendor
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Notes:
|
|
56
|
+
- The upstream project documents scope/assumptions in `SOUNDNESS.md`; review this when making compliance assertions.
|
|
57
|
+
- This package uses ML-KEM-1024 (not "1028").
|
|
13
58
|
|
|
14
59
|
## Credits
|
|
15
60
|
|
|
16
|
-
- Core
|
|
61
|
+
- Core approach adapted from Dmitry Chestnykh's `mlkem-wasm`:
|
|
17
62
|
- https://github.com/dchest/mlkem-wasm
|
|
18
63
|
|
|
19
|
-
<!-- > **Note**: 🚧 WORK IN PROGRESS...do not install 🚧 -->
|
|
20
|
-
<p align="center">
|
|
21
|
-
<img src="./kyber.png"/>
|
|
22
|
-
</p>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
## About
|
|
26
|
-
You use this quantum-resistant RustyKey® npm package mainly for secure key exchange, specifically as a Key Encapsulation Mechanism (KEM). It's designed to securely establish a shared secret between two parties, which is then used for encryption with a symmetric algorithm like AES. While Kyber can be used for encryption, its primary function is to encapsulate and transmit a session key, not the data itself.
|
|
27
|
-
|
|
28
|
-
Here's a more detailed explanation:
|
|
29
|
-
Key Exchange (KEM):
|
|
30
|
-
- to facilitate the secure exchange of a shared secret key between two parties. This shared key is then used to encrypt and decrypt data using a separate, symmetric encryption algorithm.
|
|
31
|
-
Not Direct Encryption:
|
|
32
|
-
- doesn't directly encrypt the data itself. It's designed to securely encapsulate a session key, which is then used to encrypt the actual data using a symmetric encryption algorithm.
|
|
33
|
-
Hybrid Approach:
|
|
34
|
-
- often used in a hybrid approach, combining it with symmetric encryption algorithms like AES for stronger security. Used to securely exchange a session key, then used to encrypt the data using AES.
|
|
35
|
-
Post-Quantum Security:
|
|
36
|
-
- a post-quantum cryptosystem, meaning it is designed to be secure against attacks from quantum computers. This makes it a valuable tool for securing communication in the future when quantum computers become more powerful.
|
|
37
|
-
|
|
38
|
-
In essence, RustyKey® quantum-resistant npm package creates a secure handshake, establishing a shared secret key that can then be used to encrypt and decrypt data with a more efficient symmetric encryption algorithm
|
|
39
|
-
|
|
40
|
-
## Web Assembly implementation
|
|
41
|
-
### Pros
|
|
42
|
-
#### Highly secure
|
|
43
|
-
Wasm operates within a sandboxed environment, isolating it from the host system. This prevents malicious code within the Wasm module from directly accessing sensitive data or compromising system resources. JavaScript, while also sandboxed, has a larger attack surface due to its dynamic nature and access to a wider range of APIs.
|
|
44
|
-
#### Reduced Attack Surface
|
|
45
|
-
Since Wasm modules have limited access to system resources and APIs, their attack surface is smaller than that of JavaScript. This makes it more difficult for attackers to exploit vulnerabilities.
|
|
46
|
-
#### fast
|
|
47
|
-
(mostly!) as Web Assembly (WASM) implementations of algorithms offer near-native performance due to WASM's low-level of bytecode, which itself is usually orders of magnitude faster than JavaScript for computationally intensive tasks.
|
|
48
|
-
#### Controlled Imports
|
|
49
|
-
Wasm modules have explicit import declarations, defining the exact functions they can access from the host environment (usually JavaScript). This allows for fine-grained control over the module's capabilities. In contrast, JavaScript has more implicit access to APIs, making it harder to restrict its behavior.
|
|
50
|
-
#### Static Analysis
|
|
51
|
-
Wasm's binary format allows for static analysis and code validation. This enables browsers to verify the module's structure and behavior before execution, reducing the risk of introducing vulnerabilities. JavaScript, being dynamically typed and interpreted, is more challenging to analyze statically.
|
|
52
|
-
#### Compilation and Validation
|
|
53
|
-
Wasm code is compiled into a low-level bytecode that is validated before execution. This process helps to identify and prevent many types of vulnerabilities that are common in JavaScript, such as buffer overflows.
|
|
54
|
-
|
|
55
|
-
### Cons
|
|
56
|
-
#### Complex
|
|
57
|
-
WASM is more complex to work with than JavaScript, and requires a build process to compile code into WASM modules and manual memory management, which is why this package exists...to make it easier for developers and end-users to incorporate the benefits of increased security and faster speed into their authentication, authorization and other encryption/decryption workflows.
|
|
58
|
-
|
|
59
|
-
#### No Direct DOM Access
|
|
60
|
-
WASM cannot directly manipulate the DOM. It relies on JavaScript to interact with the DOM, which adds complexity and can affect performance when frequent DOM interactions are needed.
|
|
61
|
-
#### Garbage Collection
|
|
62
|
-
WASM relies on JavaScript for garbage collection, which can be less efficient compared to languages with native garbage collection.
|
|
63
|
-
#### Limited API Access
|
|
64
|
-
WASM has limited access to browser and Node.js APIs compared to JavaScript, requiring JavaScript to act as a bridge for these interactions.
|
|
65
|
-
#### Data Transfer Overhead
|
|
66
|
-
Passing data between WASM and JavaScript can incur performance overhead due to serialization and deserialization.
|
|
67
|
-
|
|
68
|
-
### Algorithm source
|
|
69
|
-
Based on a suite 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](https://pq-crystals.org/index.shtml)
|
|
70
|
-
|
|
71
|
-
| Package | Registry | Description |
|
|
72
|
-
|---------|----------|-------------|
|
|
73
|
-
| quantum-resistant-rustykey | [](https://www.npmjs.com/package/quantum-resistant-rustykey) | 🚧 WORK IN PROGRESS 🚧 |
|
|
74
|
-
|
|
75
64
|
## Installation
|
|
76
65
|
|
|
77
|
-
|
|
66
|
+
Install via pnpm, npm or yarn:
|
|
78
67
|
|
|
79
68
|
```bash
|
|
80
69
|
pnpm install quantum-resistant-rustykey
|
|
@@ -86,7 +75,7 @@ yarn add quantum-resistant-rustykey
|
|
|
86
75
|
|
|
87
76
|
## Usage
|
|
88
77
|
|
|
89
|
-
### Node.js
|
|
78
|
+
### Node.js example
|
|
90
79
|
|
|
91
80
|
```typescript
|
|
92
81
|
import { loadMlKem1024, loadMlKem768, loadMlKem512 } from "quantum-resistant-rustykey";
|
|
@@ -105,13 +94,13 @@ async function main() {
|
|
|
105
94
|
|
|
106
95
|
// Encrypt a message
|
|
107
96
|
const message = "Hello, this is a secret message!";
|
|
108
|
-
|
|
97
|
+
const encrypt = mlkem.encrypt(keypair.get('public_key'))
|
|
109
98
|
const sharedSecret = encrypt.get('secret')
|
|
110
99
|
const encryptedMessage = await mlkem.encryptMessage(message, sharedSecret)
|
|
111
100
|
console.log("Encrypted message: ", encryptedMessage)
|
|
112
101
|
|
|
113
102
|
// Decrypt the message
|
|
114
|
-
|
|
103
|
+
const decryptedSharedSecret = mlkem.decrypt(encrypt.get('cyphertext'), keypair.get('private_key'))
|
|
115
104
|
const decryptedMessage = await mlkem.decryptMessage(encryptedMessage, decryptedSharedSecret)
|
|
116
105
|
console.log("Decrypted message: ", decryptedMessage)
|
|
117
106
|
} catch (error) {
|
|
@@ -122,38 +111,45 @@ async function main() {
|
|
|
122
111
|
main();
|
|
123
112
|
```
|
|
124
113
|
|
|
125
|
-
###
|
|
114
|
+
### Frontend example (Vite / browser)
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { loadMlKem768 } from "quantum-resistant-rustykey";
|
|
118
|
+
|
|
119
|
+
const output = document.querySelector("#output");
|
|
126
120
|
|
|
127
|
-
|
|
121
|
+
async function run() {
|
|
122
|
+
const kem = await loadMlKem768();
|
|
123
|
+
const kp = kem.keypair();
|
|
128
124
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- Consider using the Web Crypto API for additional security
|
|
125
|
+
const enc = kem.encrypt(kp.get("public_key"));
|
|
126
|
+
const sharedSecretA = await enc.get("secret");
|
|
127
|
+
const sharedSecretB = await kem.decrypt(enc.get("cyphertext"), kp.get("private_key"));
|
|
133
128
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- Implement proper key rotation policies
|
|
137
|
-
- Consider using a key management service for production applications
|
|
129
|
+
const encrypted = await kem.encryptMessage("hello from browser", sharedSecretA);
|
|
130
|
+
const decrypted = await kem.decryptMessage(encrypted, sharedSecretB);
|
|
138
131
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- Use HTTPS for all communications
|
|
142
|
-
- Implement proper error handling to prevent information leakage
|
|
132
|
+
output.textContent = decrypted;
|
|
133
|
+
}
|
|
143
134
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
135
|
+
run().catch((err) => {
|
|
136
|
+
console.error(err);
|
|
137
|
+
output.textContent = "failed";
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Security note for web apps:
|
|
142
|
+
- never store private keys in `localStorage`/`sessionStorage`
|
|
143
|
+
- prefer HTTPS + short-lived keys
|
|
144
|
+
- use secure key storage strategy (e.g. IndexedDB + app-level protections)
|
|
148
145
|
|
|
149
146
|
## Building from Source
|
|
150
147
|
|
|
151
148
|
### Prerequisites
|
|
152
149
|
|
|
153
|
-
- Node.js >=
|
|
154
|
-
- pnpm (
|
|
155
|
-
- Emscripten
|
|
156
|
-
- CMake
|
|
150
|
+
- Node.js >= 22 (LTS)
|
|
151
|
+
- pnpm (or npm)
|
|
152
|
+
- Emscripten **or** Docker — only needed if you run `pnpm build:vendor` to regenerate `src/vendor/mlkem*.js`
|
|
157
153
|
|
|
158
154
|
### Build Instructions
|
|
159
155
|
|
|
@@ -163,73 +159,55 @@ git clone https://github.com/antonymott/quantum-resistant-rustykey.git
|
|
|
163
159
|
cd quantum-resistant-rustykey
|
|
164
160
|
```
|
|
165
161
|
|
|
166
|
-
|
|
167
|
-
2. Initialize submodules:
|
|
162
|
+
2. Install dependencies:
|
|
168
163
|
```bash
|
|
169
|
-
|
|
164
|
+
pnpm i
|
|
170
165
|
```
|
|
171
166
|
|
|
172
|
-
3.
|
|
167
|
+
3. (Optional) Clone [mlkem-native](https://github.com/pq-code-package/mlkem-native) if you will regenerate vendored bundles:
|
|
173
168
|
```bash
|
|
174
|
-
|
|
169
|
+
git clone --depth 1 https://github.com/pq-code-package/mlkem-native.git vendor/mlkem-native
|
|
175
170
|
```
|
|
176
171
|
|
|
177
|
-
4.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
The package supports two different environments:
|
|
172
|
+
4. (Optional) Rebuild `src/vendor/mlkem*.js` after changing `wasm/` or `mlkem-src/` (requires `emcc` or Docker):
|
|
173
|
+
```bash
|
|
174
|
+
pnpm build:vendor
|
|
175
|
+
```
|
|
182
176
|
|
|
183
|
-
|
|
184
|
-
- **Node.js Environment**: Set `sENVIRONMENT=node,worker` in CMakeLists.txt
|
|
177
|
+
5. Compile TypeScript to `dist/`:
|
|
185
178
|
|
|
186
179
|
```bash
|
|
187
|
-
pnpm
|
|
188
|
-
|
|
189
|
-
# Copy the WASM file to src directory
|
|
190
|
-
cp install/kyber_crystals_wasm_engine.wasm ./src/
|
|
180
|
+
pnpm build
|
|
191
181
|
```
|
|
192
182
|
|
|
193
|
-
The `sENVIRONMENT` option specifies which environments the WebAssembly module should be built for:
|
|
194
|
-
- `web`: Enables running in web browsers
|
|
195
|
-
- `worker`: Enables running in Web Workers
|
|
196
|
-
- `node`: Enables running in Node.js
|
|
197
183
|
|
|
198
|
-
|
|
199
|
-
|
|
184
|
+
## Testing
|
|
185
|
+
|
|
186
|
+
- Run `pnpm test` for ML-KEM-512 / 768 / 1024 round-trips.
|
|
187
|
+
|
|
188
|
+
## Browser example (local)
|
|
200
189
|
|
|
201
|
-
|
|
190
|
+
A Vite app under `examples/browser-demo` links this package from the workspace. From the repo root:
|
|
202
191
|
|
|
203
192
|
```bash
|
|
204
193
|
pnpm build
|
|
194
|
+
pnpm example:browser
|
|
205
195
|
```
|
|
206
196
|
|
|
207
|
-
|
|
208
|
-
## Testing
|
|
209
|
-
|
|
210
|
-
- Tested to work with Node.js v25.9.0
|
|
211
|
-
- For web testing, open `install/test.html` in a live server and check the console for encryption/decryption results of the three variants
|
|
197
|
+
See `examples/browser-demo/README.md` for details.
|
|
212
198
|
|
|
213
199
|
## Project Structure
|
|
214
200
|
|
|
215
|
-
|
|
216
|
-
stateDiagram-v2
|
|
217
|
-
[*] --> install
|
|
218
|
-
install --> [*]
|
|
219
|
-
install --> kyber_crystals_wasm_engine.js
|
|
220
|
-
kyber_crystals_wasm_engine.js --> kyber_crystals_wasm_engine.wasm
|
|
221
|
-
kyber_crystals_wasm_engine.wasm --> test.html
|
|
222
|
-
test.html --> [*]
|
|
223
|
-
```
|
|
201
|
+
ML-KEM logic comes from **mlkem-native** (C), compiled with **Emscripten** under `wasm/`, wrapped by TypeScript derived from [mlkem-wasm](https://github.com/dchest/mlkem-wasm) in `mlkem-src/`, then bundled into `src/vendor/mlkem*.js`.
|
|
224
202
|
|
|
225
203
|
## Publishing
|
|
226
204
|
|
|
227
|
-
The package is published from the `
|
|
205
|
+
The package is published from the npm package root (`dist/`). To publish a new version:
|
|
228
206
|
1. make a new branch locally from main
|
|
229
207
|
2. edit and test your changes
|
|
230
208
|
3. pnpm changeset
|
|
231
|
-
4.
|
|
232
|
-
5.
|
|
209
|
+
4. `pnpm lint && pnpm test && pnpm build`
|
|
210
|
+
5. merge to main; CI publishes when the version changed
|
|
233
211
|
|
|
234
212
|
## Security Considerations
|
|
235
213
|
|