@vollcrypt/messages-wasm 0.9.0 → 0.9.1
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/CHANGELOG.md +49 -0
- package/LICENSE +16 -0
- package/LICENSE-COMMERCIAL.md +71 -0
- package/LICENSE-GPL +674 -0
- package/README.md +679 -34
- package/fast.d.ts +2 -2
- package/package.json +25 -3
- package/pkg/README.md +705 -0
- package/pkg/wasm.d.ts +328 -0
- package/pkg/wasm.js +1835 -0
- package/pkg/wasm_bg.wasm +0 -0
- package/pkg/wasm_bg.wasm.d.ts +100 -0
package/pkg/README.md
ADDED
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>Vollcrypt Messages</h1>
|
|
3
|
+
<p><strong>E2EE Message Encryption and Session Management module for Node.js, WebAssembly, and Rust</strong></p>
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://www.npmjs.com/package/@vollcrypt/messages-node">
|
|
7
|
+
<img src="https://img.shields.io/npm/v/@vollcrypt/messages-node?label=%40vollcrypt%2Fmessages-node&color=cb3837" alt="npm (node)">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@vollcrypt/messages-wasm">
|
|
10
|
+
<img src="https://img.shields.io/npm/v/@vollcrypt/messages-wasm?label=%40vollcrypt%2Fmessages-wasm&color=cb3837" alt="npm (wasm)">
|
|
11
|
+
</a>
|
|
12
|
+
</p>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
This module contains the cryptographic primitives and session managers needed to build secure end-to-end encrypted (E2EE) messaging systems. It is compiled from a single Rust core to three targets: Node.js (native bindings), WebAssembly, and native Rust.
|
|
18
|
+
|
|
19
|
+
## Table of Contents
|
|
20
|
+
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Quick Start](#quick-start)
|
|
23
|
+
- [API Reference](#api-reference)
|
|
24
|
+
- [Identity and Key Exchange](#identity-and-key-exchange)
|
|
25
|
+
- [Post-Quantum Cryptography](#post-quantum-cryptography)
|
|
26
|
+
- [Symmetric Encryption](#symmetric-encryption)
|
|
27
|
+
- [Key Derivation](#key-derivation)
|
|
28
|
+
- [Session Security (PCS Ratchet & Hashing)](#session-security)
|
|
29
|
+
- [Sealed Sender](#sealed-sender)
|
|
30
|
+
- [Key Verification Codes](#key-verification-codes)
|
|
31
|
+
- [Key Transparency Log](#key-transparency-log)
|
|
32
|
+
- [Device Registry](#device-registry)
|
|
33
|
+
- [Full E2EE Flow Example](#full-e2ee-flow-example)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
### Node.js (Server-side & Native Addon)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @vollcrypt/messages-node
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Prebuilt native binaries are provided for:
|
|
46
|
+
- Linux x64 (`linux-x64-gnu`)
|
|
47
|
+
- macOS x64 (`darwin-x64`)
|
|
48
|
+
- Windows x64 (`win32-x64-msvc`)
|
|
49
|
+
|
|
50
|
+
### WebAssembly (Browser / React / Next.js)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install @vollcrypt/messages-wasm
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Rust (Cargo)
|
|
57
|
+
|
|
58
|
+
In a Cargo workspace:
|
|
59
|
+
```toml
|
|
60
|
+
vollcrypt-core = { path = "../vollcrypt/src/core" }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
### Node.js — Generate Keys and Encrypt a Message
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import {
|
|
71
|
+
generateEd25519Keypair,
|
|
72
|
+
encryptAesGcm,
|
|
73
|
+
decryptAesGcm,
|
|
74
|
+
} from '@vollcrypt/messages-node';
|
|
75
|
+
import crypto from 'crypto';
|
|
76
|
+
|
|
77
|
+
// Identity keypair
|
|
78
|
+
const [identitySecret, identityPublic] = generateEd25519Keypair();
|
|
79
|
+
|
|
80
|
+
// Session key (in practice, derived via KEM handshake)
|
|
81
|
+
const sessionKey = crypto.randomBytes(32);
|
|
82
|
+
const plaintext = Buffer.from('Hello, Vollcrypt');
|
|
83
|
+
|
|
84
|
+
// Encrypt
|
|
85
|
+
const ciphertext = encryptAesGcm(sessionKey, plaintext, null);
|
|
86
|
+
|
|
87
|
+
// Decrypt
|
|
88
|
+
const decrypted = decryptAesGcm(sessionKey, ciphertext, null);
|
|
89
|
+
console.log(decrypted.toString()); // Hello, Vollcrypt
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### WebAssembly — Browser
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import init, {
|
|
96
|
+
generateEd25519Keypair,
|
|
97
|
+
encryptAesGcm,
|
|
98
|
+
decryptAesGcm,
|
|
99
|
+
} from '@vollcrypt/messages-wasm';
|
|
100
|
+
|
|
101
|
+
await init();
|
|
102
|
+
|
|
103
|
+
const [identitySecret, identityPublic] = generateEd25519Keypair();
|
|
104
|
+
const sessionKey = crypto.getRandomValues(new Uint8Array(32));
|
|
105
|
+
const plaintext = new TextEncoder().encode('Hello, Vollcrypt');
|
|
106
|
+
|
|
107
|
+
const ciphertext = encryptAesGcm(sessionKey, plaintext, null);
|
|
108
|
+
const decrypted = decryptAesGcm(sessionKey, ciphertext, null);
|
|
109
|
+
console.log(new TextDecoder().decode(decrypted));
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Architecture and Protocol Design
|
|
115
|
+
|
|
116
|
+
The Vollcrypt messages module provides the core cryptographic mechanisms to build end-to-end encrypted sessions between endpoints. The state machine enforces Perfect Forward Secrecy (PFS) through time-windowed ratchets, and Post-Compromise Security (PCS) through X25519 Diffie-Hellman ratcheting.
|
|
117
|
+
|
|
118
|
+
### E2EE Lifecycle Sequence Diagram
|
|
119
|
+
|
|
120
|
+
```mermaid
|
|
121
|
+
sequenceDiagram
|
|
122
|
+
autonumber
|
|
123
|
+
actor Alice as Alice (Client)
|
|
124
|
+
actor Bob as Bob (Client)
|
|
125
|
+
participant Server as Directory Server / KTransparency
|
|
126
|
+
|
|
127
|
+
Note over Bob: Generates Identity Keypair (Ed25519)<br/>Ratchet Keypair (X25519)<br/>PQ KEM Keypair (ML-KEM-768)
|
|
128
|
+
Bob->>Server: Register and upload Bob's public keys
|
|
129
|
+
Server->>Server: Append Bob's keys to signed Key Transparency Log
|
|
130
|
+
|
|
131
|
+
Note over Alice: Generates Identity Keypair (Ed25519)
|
|
132
|
+
Alice->>Server: Query Bob's public keys
|
|
133
|
+
Server-->>Alice: Bob's (X25519_pub, MLKEM_pub) + Signature verification
|
|
134
|
+
|
|
135
|
+
Note over Alice: authenticated_kem_encapsulate(<br/>Alice_X25519_sk, Bob_X25519_pub, Bob_MLKEM_pub, Alice_ID_sk<br/>) -> (ciphertext, shared_secret)
|
|
136
|
+
Note over Alice: Derive SRK & WindowKey_n<br/>encrypt_aes_gcm(payload, window_key) -> ciphertext
|
|
137
|
+
Note over Alice: pack_envelope() -> sealed_packet
|
|
138
|
+
Alice->>Server: Deliver sealed_packet (recipient: Bob)
|
|
139
|
+
Server->>Bob: Forward sealed_packet
|
|
140
|
+
|
|
141
|
+
Note over Bob: unpack_envelope(sealed_packet)
|
|
142
|
+
Note over Bob: authenticated_kem_decapsulate(<br/>Bob_X25519_sk, Alice_X25519_pub, Bob_MLKEM_dk, ciphertext, Alice_ID_pk<br/>) -> shared_secret
|
|
143
|
+
Note over Bob: Verify Alice's signature on ciphertext
|
|
144
|
+
Note over Bob: Derive Bob's WindowKey_n & Decrypt payload
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## API Reference
|
|
150
|
+
|
|
151
|
+
The APIs are exposed in both the Node.js native binding (`@vollcrypt/messages-node`) and the WebAssembly binding (`@vollcrypt/messages-wasm`).
|
|
152
|
+
|
|
153
|
+
* **JavaScript/TypeScript target types:** Both bindings expose the identical **camelCase** naming convention. In Node.js, functions accept/return `Buffer` (or `Uint8Array`), whereas in WASM, functions accept/return standard browser `Uint8Array` views.
|
|
154
|
+
* **Rust target:** Native Rust developers should consume the `vollcrypt-core` crate directly, which exposes identical logic via **snake_case** functions.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 1. Identity and Key Exchange
|
|
159
|
+
|
|
160
|
+
#### `generateEd25519Keypair() → [secretKey: Buffer, publicKey: Buffer]`
|
|
161
|
+
Generates a new Ed25519 keypair for user or device signing identity.
|
|
162
|
+
* **Returns:** Array containing the `secretKey` (64 bytes) and `publicKey` (32 bytes).
|
|
163
|
+
|
|
164
|
+
#### `signMessage(secretKey: Uint8Array, message: Uint8Array) → Buffer`
|
|
165
|
+
Signs a message with an Ed25519 private key.
|
|
166
|
+
* **Parameters:**
|
|
167
|
+
* `secretKey`: 64-byte Ed25519 private key buffer.
|
|
168
|
+
* `message`: Arbitrary binary buffer to sign.
|
|
169
|
+
* **Returns:** 64-byte Ed25519 signature buffer.
|
|
170
|
+
* **Errors:** Throws an exception if the secret key length is invalid.
|
|
171
|
+
|
|
172
|
+
#### `verifySignature(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array) → boolean`
|
|
173
|
+
Verifies an Ed25519 digital signature.
|
|
174
|
+
* **Parameters:**
|
|
175
|
+
* `publicKey`: 32-byte Ed25519 public key.
|
|
176
|
+
* `message`: Signed payload.
|
|
177
|
+
* `signature`: 64-byte signature to verify.
|
|
178
|
+
* **Returns:** `true` if the signature is valid; `false` otherwise.
|
|
179
|
+
|
|
180
|
+
#### `generateX25519Keypair() → [secretKey: Buffer, publicKey: Buffer]`
|
|
181
|
+
Generates a new X25519 Diffie-Hellman keypair for classical key exchange.
|
|
182
|
+
* **Returns:** Array containing the X25519 `secretKey` (32 bytes) and `publicKey` (32 bytes).
|
|
183
|
+
|
|
184
|
+
#### `ecdhSharedSecret(ourSecret: Uint8Array, theirPublic: Uint8Array) → Buffer`
|
|
185
|
+
Computes an X25519 ECDH shared secret.
|
|
186
|
+
* **Parameters:**
|
|
187
|
+
* `ourSecret`: 32-byte X25519 secret key.
|
|
188
|
+
* `theirPublic`: 32-byte X25519 public key.
|
|
189
|
+
* **Returns:** 32-byte computed shared secret.
|
|
190
|
+
* **Errors:** Throws if input lengths do not equal 32 bytes.
|
|
191
|
+
|
|
192
|
+
#### `generateMnemonic() → string`
|
|
193
|
+
Generates a new random English BIP-39 mnemonic phrase containing 24 words (256-bit entropy).
|
|
194
|
+
* **Returns:** A 24-word string separated by spaces.
|
|
195
|
+
|
|
196
|
+
#### `mnemonicToSeed(phrase: string, password?: string | null) → Buffer`
|
|
197
|
+
Converts a BIP-39 mnemonic phrase to a 64-byte binary seed.
|
|
198
|
+
* **Parameters:**
|
|
199
|
+
* `phrase`: The 24-word mnemonic string.
|
|
200
|
+
* `password`: Optional passphrase/password protection (salt) string.
|
|
201
|
+
* **Returns:** 64-byte seed.
|
|
202
|
+
* **Errors:** Throws if the mnemonic phrase is invalid or has a wrong checksum.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### 2. Post-Quantum Cryptography (PQC)
|
|
207
|
+
|
|
208
|
+
#### `mlKemKeygen() → [decapsKey: Buffer, encapsKey: Buffer]`
|
|
209
|
+
Generates a new ML-KEM-768 keypair (NIST FIPS 203).
|
|
210
|
+
* **Returns:** Array containing the `decapsulationKey` (2400 bytes) and `encapsulationKey` (1184 bytes).
|
|
211
|
+
|
|
212
|
+
#### `mlKemEncapsulate(encapsulationKey: Uint8Array) → MlKemEncapsulationResult`
|
|
213
|
+
Performs ML-KEM-768 key encapsulation.
|
|
214
|
+
* **Parameters:**
|
|
215
|
+
* `encapsulationKey`: 1184-byte ML-KEM public key.
|
|
216
|
+
* **Returns:** Object with:
|
|
217
|
+
* `ciphertext`: Buffer (1088 bytes) to transmit.
|
|
218
|
+
* `sharedSecret`: Buffer (32 bytes) derived key.
|
|
219
|
+
* **Errors:** Throws if the key size is incorrect.
|
|
220
|
+
|
|
221
|
+
#### `mlKemDecapsulate(decapsulationKey: Uint8Array, ciphertext: Uint8Array) → Buffer`
|
|
222
|
+
Decapsulates a KEM ciphertext to extract the shared secret.
|
|
223
|
+
* **Parameters:**
|
|
224
|
+
* `decapsulationKey`: 2400-byte ML-KEM private key.
|
|
225
|
+
* `ciphertext`: 1088-byte encapsulated ciphertext.
|
|
226
|
+
* **Returns:** 32-byte shared secret.
|
|
227
|
+
* **Errors:** Throws if inputs are malformed.
|
|
228
|
+
|
|
229
|
+
#### `hybridKemEncapsulate(x25519OurSecret: Uint8Array, x25519TheirPublic: Uint8Array, mlKemEk: Uint8Array) → HybridKemResult`
|
|
230
|
+
Performs a hybrid KEM encapsulation combining X25519 and ML-KEM-768.
|
|
231
|
+
* **Parameters:**
|
|
232
|
+
* `x25519OurSecret`: Alice's ephemeral 32-byte X25519 secret key.
|
|
233
|
+
* `x25519TheirPublic`: Bob's static 32-byte X25519 public key.
|
|
234
|
+
* `mlKemEk`: Bob's static 1184-byte ML-KEM encapsulation key.
|
|
235
|
+
* **Returns:** Object with:
|
|
236
|
+
* `sharedKey`: Buffer (32 bytes) derived via HKDF-SHA256.
|
|
237
|
+
* `mlKemCiphertext`: Buffer (1088 bytes) KEM output.
|
|
238
|
+
|
|
239
|
+
#### `hybridKemDecapsulate(x25519OurSecret: Uint8Array, x25519TheirPublic: Uint8Array, mlKemDk: Uint8Array, mlKemCt: Uint8Array) → Buffer`
|
|
240
|
+
Decapsulates a hybrid KEM ciphertext.
|
|
241
|
+
* **Parameters:**
|
|
242
|
+
* `x25519OurSecret`: Bob's static X25519 secret key.
|
|
243
|
+
* `x25519TheirPublic`: Alice's ephemeral X25519 public key.
|
|
244
|
+
* `mlKemDk`: Bob's static ML-KEM private key.
|
|
245
|
+
* `mlKemCt`: 1088-byte ML-KEM ciphertext.
|
|
246
|
+
* **Returns:** 32-byte derived shared key.
|
|
247
|
+
|
|
248
|
+
#### `authenticatedKemEncapsulate(ourX25519Sk: Uint8Array, recipientX25519Pub: Uint8Array, recipientMlkemEk: Uint8Array, senderIdentitySk: Uint8Array) → [ciphertext: Buffer, sharedSecret: Buffer]`
|
|
249
|
+
Performs a hybrid KEM encapsulation and signs the ciphertext with the sender's Ed25519 identity key.
|
|
250
|
+
* **Parameters:**
|
|
251
|
+
* `ourX25519Sk`: Sender's ephemeral X25519 secret key.
|
|
252
|
+
* `recipientX25519Pub`: Recipient's static X25519 public key.
|
|
253
|
+
* `recipientMlkemEk`: Recipient's static ML-KEM public key.
|
|
254
|
+
* `senderIdentitySk`: Sender's static Ed25519 signing secret key.
|
|
255
|
+
* **Returns:** Array containing the signed KEM `ciphertext` (1154 bytes) and the `sharedSecret` (32 bytes).
|
|
256
|
+
|
|
257
|
+
#### `authenticatedKemDecapsulate(ourX25519Sk: Uint8Array, senderX25519Pub: Uint8Array, ourMlkemDk: Uint8Array, authenticatedCiphertext: Uint8Array, senderIdentityPk: Uint8Array) → Buffer`
|
|
258
|
+
Verifies the sender's signature before decapsulating the hybrid shared secret.
|
|
259
|
+
* **Parameters:**
|
|
260
|
+
* `ourX25519Sk`: Bob's static X25519 secret key.
|
|
261
|
+
* `senderX25519Pub`: Alice's ephemeral X25519 public key.
|
|
262
|
+
* `ourMlkemDk`: Bob's static ML-KEM decapsulation key.
|
|
263
|
+
* `authenticatedCiphertext`: The signed KEM ciphertext.
|
|
264
|
+
* `senderIdentityPk`: Alice's static Ed25519 identity public key.
|
|
265
|
+
* **Returns:** 32-byte shared secret.
|
|
266
|
+
* **Errors:** Throws if the Ed25519 signature is invalid, refusing KEM negotiation.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
### 3. Symmetric Encryption (AES-GCM)
|
|
271
|
+
|
|
272
|
+
All symmetric algorithms use AES-256-GCM. Nonces/IVs are 12 bytes and are generated internally using a cryptographically secure random number generator (`OsRng`).
|
|
273
|
+
|
|
274
|
+
#### `encryptAesGcm(key: Uint8Array, plaintext: Uint8Array, aad?: Uint8Array | null) → Buffer`
|
|
275
|
+
Encrypts payload. The internally generated 12-byte IV is prepended to the returned ciphertext.
|
|
276
|
+
* **Parameters:**
|
|
277
|
+
* `key`: 32-byte encryption key.
|
|
278
|
+
* `plaintext`: Raw data to encrypt.
|
|
279
|
+
* `aad`: Optional Additional Authenticated Data.
|
|
280
|
+
* **Returns:** Ciphertext buffer with a length of `12 + plaintext.length + 16` bytes.
|
|
281
|
+
|
|
282
|
+
#### `decryptAesGcm(key: Uint8Array, ciphertext: Uint8Array, aad?: Uint8Array | null) → Buffer`
|
|
283
|
+
Decrypts and validates an AES-GCM ciphertext. Assumes a prepended 12-byte IV.
|
|
284
|
+
* **Parameters:**
|
|
285
|
+
* `key`: 32-byte encryption key.
|
|
286
|
+
* `ciphertext`: Ciphertext buffer (containing the 12-byte IV prepended).
|
|
287
|
+
* `aad`: Optional Additional Authenticated Data.
|
|
288
|
+
* **Returns:** Decrypted plaintext.
|
|
289
|
+
* **Errors:** Throws on key length errors or authentication tag mismatch (tampering).
|
|
290
|
+
|
|
291
|
+
#### `encryptAesGcmPadded(key: Uint8Array, plaintext: Uint8Array, aad?: Uint8Array | null) → Buffer`
|
|
292
|
+
Encrypts plaintext after padding it to standard boundaries (using PKCS#7 padding) to hide message size.
|
|
293
|
+
|
|
294
|
+
#### `decryptAesGcmPadded(key: Uint8Array, ciphertext: Uint8Array, aad?: Uint8Array | null) → Buffer`
|
|
295
|
+
Decrypts and removes PKCS#7 padding.
|
|
296
|
+
|
|
297
|
+
#### `encryptAesGcmChunked(key: Uint8Array, plaintext: Uint8Array, aad: Uint8Array | null, chunkSize: number) → Buffer`
|
|
298
|
+
Splits payload into multiple chunks of size `chunkSize` and encrypts each independently.
|
|
299
|
+
|
|
300
|
+
#### `decryptAesGcmChunked(key: Uint8Array, ciphertext: Uint8Array, aad?: Uint8Array | null) → Buffer`
|
|
301
|
+
Decrypts a chunked ciphertext stream.
|
|
302
|
+
|
|
303
|
+
#### `padMessage(content: Uint8Array) → Buffer`
|
|
304
|
+
Pads message data according to PKCS#7 standard block padding.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### 4. Key Derivation and Wrapping
|
|
309
|
+
|
|
310
|
+
#### `derivePbkdf2(password: Uint8Array, salt: Uint8Array, iterations: number, keyLen: number) → Buffer`
|
|
311
|
+
Derives a key from a password using PBKDF2-SHA256.
|
|
312
|
+
* **Security Policy:** Always use at least **600,000 iterations** for password-based key wrapping.
|
|
313
|
+
|
|
314
|
+
#### `deriveHkdf(ikm: Uint8Array, salt: Uint8Array | null, info: Uint8Array | null, keyLen: number) → Buffer`
|
|
315
|
+
Derives a cryptographically strong key from input keying material (IKM) using HKDF-SHA256.
|
|
316
|
+
|
|
317
|
+
#### `deriveSrk(dek: Uint8Array, chatId: Uint8Array) → Buffer`
|
|
318
|
+
Derives a 32-byte Session Root Key (SRK) from a Data Encryption Key (DEK) and a unique chat identifier.
|
|
319
|
+
|
|
320
|
+
#### `deriveWindowKey(srk: Uint8Array, windowIndex: number) → Buffer`
|
|
321
|
+
Derives a time-window-specific encryption key from the Session Root Key.
|
|
322
|
+
* `windowIndex`: `floor(UNIX_timestamp / window_size_seconds)`.
|
|
323
|
+
|
|
324
|
+
#### `wrapKey(kek: Uint8Array, keyToWrap: Uint8Array) → Buffer`
|
|
325
|
+
Wraps a key using AES-256 Key Wrap (AES-KW, RFC 3394) under a Key Encryption Key (KEK).
|
|
326
|
+
* **Errors:** Throws if input lengths are invalid.
|
|
327
|
+
|
|
328
|
+
#### `unwrapKey(kek: Uint8Array, wrappedKey: Uint8Array) → Buffer`
|
|
329
|
+
Unwraps an AES-KW wrapped key.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
### 5. Session Security & Ratcheting
|
|
334
|
+
|
|
335
|
+
#### `generateRatchetKeypair() → [secretKey: Buffer, publicKey: Buffer]`
|
|
336
|
+
Generates a new ephemeral X25519 keypair for Post-Compromise Security (PCS) ratcheting steps.
|
|
337
|
+
|
|
338
|
+
#### `ratchetSrk(currentSrk: Uint8Array, ourRatchetSecret: Uint8Array, theirRatchetPub: Uint8Array, chatId: Uint8Array, ratchetStep: number, isSender: boolean) → Buffer`
|
|
339
|
+
Advances the Session Root Key (SRK) with an ephemeral ECDH exchange value.
|
|
340
|
+
* **Parameters:**
|
|
341
|
+
* `currentSrk`: Current 32-byte Session Root Key.
|
|
342
|
+
* `ourRatchetSecret`: Our ephemeral 32-byte X25519 secret key.
|
|
343
|
+
* `theirRatchetPub`: Their ephemeral X25519 public key.
|
|
344
|
+
* `chatId`: Unique conversation identifier.
|
|
345
|
+
* `ratchetStep`: Monotonic counter representing the ratchet step.
|
|
346
|
+
* `isSender`: True if computing as the sender of the ratcheted message.
|
|
347
|
+
* **Returns:** 32-byte newly derived SRK. Old SRK must be zeroed immediately.
|
|
348
|
+
|
|
349
|
+
#### `shouldRatchet(messageCount: number, windowChanged: boolean, messagesPerRatchet: number, ratchetOnNewWindow: boolean) → boolean`
|
|
350
|
+
Utility logic to check if the client is due to rotate keys.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### 6. Transcript Hashing
|
|
355
|
+
|
|
356
|
+
Transcript hashing provides replay, deletion, and out-of-order message insertion detection by linking each message to the historical chain hash state.
|
|
357
|
+
|
|
358
|
+
#### `transcriptNew(sessionId: Uint8Array) → Buffer`
|
|
359
|
+
Initializes a new transcript chain state.
|
|
360
|
+
* **Returns:** 32-byte initial chain hash (`SHA-256(sessionId)`).
|
|
361
|
+
|
|
362
|
+
#### `transcriptComputeMessageHash(messageId: Uint8Array, senderId: Uint8Array, timestamp: number, ciphertext: Uint8Array) → Buffer`
|
|
363
|
+
Computes the SHA-256 hash of a message envelope.
|
|
364
|
+
* **Returns:** 32-byte message hash.
|
|
365
|
+
|
|
366
|
+
#### `transcriptUpdate(chainState: Uint8Array, messageHash: Uint8Array) → Buffer`
|
|
367
|
+
Updates the running chain state.
|
|
368
|
+
* `new_chain = SHA-256(old_chain || messageHash)`.
|
|
369
|
+
|
|
370
|
+
#### `transcriptVerifySync(hashA: Uint8Array, hashB: Uint8Array) → boolean`
|
|
371
|
+
Verifies whether two transcript hashes match using a constant-time comparison.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
### 7. Sealed Sender
|
|
376
|
+
|
|
377
|
+
#### `sealMessage(recipientX25519Pub: Uint8Array, senderId: Uint8Array, content: Uint8Array) → Buffer`
|
|
378
|
+
Encrypts the sender's identity together with the content under an ephemeral ECDH key, hiding sender metadata from routing servers.
|
|
379
|
+
|
|
380
|
+
#### `unsealMessage(sealedPacket: Uint8Array, ourX25519Sk: Uint8Array) → [senderId: Buffer, content: Buffer]`
|
|
381
|
+
Decrypts a sealed sender packet.
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
### 8. Key Verification Codes
|
|
386
|
+
|
|
387
|
+
#### `generateVerificationCode(keyA: Uint8Array, keyB: Uint8Array, conversationId: Uint8Array) → string`
|
|
388
|
+
Generates a JSON string containing out-of-band verification codes (both formatted decimal groups and emoji sequences) for human comparison.
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
### 9. Key Transparency Log
|
|
393
|
+
|
|
394
|
+
#### `keyLogCreateEntry(userId: Uint8Array, publicKey: Uint8Array, timestamp: number, prevEntryHash: Uint8Array, action: number, signingKey: Uint8Array) → string (json)`
|
|
395
|
+
Generates and signs a Key Transparency append-only log entry.
|
|
396
|
+
|
|
397
|
+
#### `keyLogVerifyChain(entriesJson: string) → boolean`
|
|
398
|
+
Verifies the integrity, signature sequence, and linkage of a JSON array of Key Transparency log entries.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
### 10. Device Registry
|
|
403
|
+
|
|
404
|
+
#### `registryEmpty() → string (json)`
|
|
405
|
+
Returns an empty device registry state object.
|
|
406
|
+
|
|
407
|
+
#### `registryAddDevice(registryJson: string, deviceId: string, name: string, addedAt: number, publicKey: string) → string (json)`
|
|
408
|
+
Adds a device public key to the registry JSON string.
|
|
409
|
+
|
|
410
|
+
#### `registryRevokeDevice(registryJson: string, deviceId: string) → string (json)`
|
|
411
|
+
Revokes a device by its ID.
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Full E2EE Flow Example
|
|
416
|
+
|
|
417
|
+
This script illustrates the complete cryptographic pipeline for generating keys, performing the Hybrid KEM handshake, deriving keys, encrypting a message via Sealed Sender, updating transcripts, and decrypting the result.
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
import {
|
|
421
|
+
generateEd25519Keypair,
|
|
422
|
+
generateX25519Keypair,
|
|
423
|
+
generateMlKem768Keypair,
|
|
424
|
+
authenticatedKemEncapsulate,
|
|
425
|
+
authenticatedKemDecapsulate,
|
|
426
|
+
deriveSrk,
|
|
427
|
+
deriveWindowKey,
|
|
428
|
+
transcriptNew,
|
|
429
|
+
transcriptComputeMessageHash,
|
|
430
|
+
transcriptUpdate,
|
|
431
|
+
transcriptVerifySync,
|
|
432
|
+
encryptAesGcm,
|
|
433
|
+
decryptAesGcm,
|
|
434
|
+
sealMessage,
|
|
435
|
+
unsealMessage
|
|
436
|
+
} from '@vollcrypt/messages-node';
|
|
437
|
+
|
|
438
|
+
// 1. Participant Identity Keypair Generation
|
|
439
|
+
const [aliceIdSk, aliceIdPk] = generateEd25519Keypair();
|
|
440
|
+
const [aliceX25519Sk, aliceX25519Pk] = generateX25519Keypair();
|
|
441
|
+
const [aliceMlkemDecaps, aliceMlkemEncaps] = generateMlKem768Keypair(); // [decaps, encaps]
|
|
442
|
+
|
|
443
|
+
const [bobIdSk, bobIdPk] = generateEd25519Keypair();
|
|
444
|
+
const [bobX25519Sk, bobX25519Pk] = generateX25519Keypair();
|
|
445
|
+
const [bobMlkemDecaps, bobMlkemEncaps] = generateMlKem768Keypair();
|
|
446
|
+
|
|
447
|
+
// 2. Hybrid Handshake Execution
|
|
448
|
+
const conversationId = Buffer.from('conv-alice-bob-001');
|
|
449
|
+
|
|
450
|
+
// Alice generates an ephemeral X25519 keypair for the hybrid KEM
|
|
451
|
+
const [aliceEphSk, aliceEphPk] = generateX25519Keypair();
|
|
452
|
+
|
|
453
|
+
// Alice encapsulates key material for Bob
|
|
454
|
+
const [authCiphertext, aliceSharedSecret] = authenticatedKemEncapsulate(
|
|
455
|
+
aliceEphSk, // Alice's ephemeral X25519 secret
|
|
456
|
+
bobX25519Pk, // Bob's static X25519 public key
|
|
457
|
+
bobMlkemEncaps, // Bob's static ML-KEM encapsulation key
|
|
458
|
+
aliceIdSk // Alice's signing key (for authentication)
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
// Bob receives Alice's ephemeral public key (extracted from handshake metadata or sent alongside)
|
|
462
|
+
// and decapsulates the shared secret
|
|
463
|
+
const bobSharedSecret = authenticatedKemDecapsulate(
|
|
464
|
+
bobX25519Sk, // Bob's static X25519 secret key
|
|
465
|
+
aliceEphPk, // Alice's ephemeral X25519 public key
|
|
466
|
+
bobMlkemDecaps, // Bob's static ML-KEM decapsulation key
|
|
467
|
+
authCiphertext, // The signed KEM ciphertext envelope
|
|
468
|
+
aliceIdPk // Alice's static Ed25519 public key
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
// 3. Key Derivation (SRK & Window Keys)
|
|
472
|
+
const aliceSrk = deriveSrk(aliceSharedSecret, conversationId);
|
|
473
|
+
const bobSrk = deriveSrk(bobSharedSecret, conversationId);
|
|
474
|
+
|
|
475
|
+
const windowIndex = Math.floor(Date.now() / 1000 / 3600);
|
|
476
|
+
const aliceWindowKey = deriveWindowKey(aliceSrk, windowIndex);
|
|
477
|
+
const bobWindowKey = deriveWindowKey(bobSrk, windowIndex);
|
|
478
|
+
|
|
479
|
+
// 4. Transcript Initialization
|
|
480
|
+
let aliceChain = transcriptNew(conversationId);
|
|
481
|
+
let bobChain = transcriptNew(conversationId);
|
|
482
|
+
|
|
483
|
+
// 5. Encrypting & Sealing the Message (Alice)
|
|
484
|
+
const messageId = Buffer.from('msg-001');
|
|
485
|
+
const senderId = Buffer.from('alice@example.com');
|
|
486
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
487
|
+
const aad = Buffer.concat([messageId, senderId, Buffer.from(timestamp.toString())]);
|
|
488
|
+
const plaintext = Buffer.from('Hello Bob');
|
|
489
|
+
|
|
490
|
+
const ciphertext = encryptAesGcm(aliceWindowKey, plaintext, aad);
|
|
491
|
+
const sealed = sealMessage(bobX25519Pk, senderId, ciphertext);
|
|
492
|
+
|
|
493
|
+
// Update Alice's Transcript chain hash state
|
|
494
|
+
const msgHash = transcriptComputeMessageHash(messageId, senderId, timestamp, ciphertext);
|
|
495
|
+
aliceChain = transcriptUpdate(aliceChain, msgHash);
|
|
496
|
+
|
|
497
|
+
// 6. Unsealing & Decrypting the Message (Bob)
|
|
498
|
+
const [revealedSender, revealedCiphertext] = unsealMessage(sealed, bobX25519Sk);
|
|
499
|
+
const decrypted = decryptAesGcm(bobWindowKey, revealedCiphertext, aad);
|
|
500
|
+
|
|
501
|
+
// Update Bob's Transcript chain hash state
|
|
502
|
+
bobChain = transcriptUpdate(bobChain, msgHash);
|
|
503
|
+
|
|
504
|
+
// 7. Verify Integrity and Equivalence
|
|
505
|
+
console.log(decrypted.toString()); // "Hello Bob"
|
|
506
|
+
console.log(transcriptVerifySync(aliceChain, bobChain)); // true
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Secure Client Integration Guidelines
|
|
512
|
+
|
|
513
|
+
When integrating `@vollcrypt/messages-node` or `@vollcrypt/messages-wasm` inside client applications, you must obey the following cryptographic safety mandates:
|
|
514
|
+
|
|
515
|
+
### 1. Active Memory Zeroization
|
|
516
|
+
JavaScript runtimes do not automatically clear memory and are vulnerable to garbage-collection delays, which leaves raw keys exposed in memory.
|
|
517
|
+
* **Clear buffers immediately after use:** Overwrite raw sensitive private keys or derived keys using `TypedArray.prototype.fill(0)`.
|
|
518
|
+
```ts
|
|
519
|
+
// Example: Zeroizing KEK or salt buffers in JS
|
|
520
|
+
const rawKey = new Uint8Array([/* secret bytes */]);
|
|
521
|
+
try {
|
|
522
|
+
// perform cryptographic operation...
|
|
523
|
+
} finally {
|
|
524
|
+
rawKey.fill(0); // Safely scrubs key from memory
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### 2. Leverage Non-Extractable CryptoKeys (Web Crypto API)
|
|
529
|
+
Never store raw public/private keys in plaintext inside Javascript context variables or state trees.
|
|
530
|
+
* When receiving raw key buffers from the WebAssembly module, immediately import them into browser-native `SubtleCrypto` with `extractable: false`.
|
|
531
|
+
* Scrub the original WASM-returned buffer immediately afterwards.
|
|
532
|
+
```ts
|
|
533
|
+
const rawWasmKey = ...; // Uint8Array
|
|
534
|
+
const cryptoKey = await window.crypto.subtle.importKey(
|
|
535
|
+
"raw",
|
|
536
|
+
rawWasmKey.buffer,
|
|
537
|
+
{ name: "AES-GCM" },
|
|
538
|
+
false, // extractable = false prevents programmatic reading via XSS
|
|
539
|
+
["encrypt", "decrypt"]
|
|
540
|
+
);
|
|
541
|
+
rawWasmKey.fill(0); // Zeroize the raw buffer
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### 3. Avoid Persistent Insecure Storage
|
|
545
|
+
* **Never** write raw secrets, seeds, or unencrypted keys to `localStorage`, `sessionStorage`, or cookies.
|
|
546
|
+
* Always wrap keys using `wrapKey()` (AES-256-KW) with a key encryption key (KEK) derived via `derivePbkdf2()` (with at least 600,000 iterations) from a user master password before writing to `IndexedDB` or local disk.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Test Coverage and Verification
|
|
551
|
+
|
|
552
|
+
Vollcrypt Messages is covered by a highly comprehensive suite of **219 unit, integration, and adversarial tests** that are run in the Rust core module.
|
|
553
|
+
|
|
554
|
+
To execute the tests:
|
|
555
|
+
```bash
|
|
556
|
+
cargo test --manifest-path vollcrypt-messages/core/Cargo.toml
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Verification Status
|
|
560
|
+
|
|
561
|
+
All tests compile warning-free and pass successfully:
|
|
562
|
+
|
|
563
|
+
| Test Category | Total Tests | Passed | Ignored | Status |
|
|
564
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
565
|
+
| **Identity and Key Exchange** | 18 | 18 | 0 | ✅ Passed |
|
|
566
|
+
| **Post-Quantum Cryptography (PQC)** | 14 | 14 | 0 | ✅ Passed |
|
|
567
|
+
| **Symmetric Encryption (AES-GCM)** | 35 | 35 | 0 | ✅ Passed |
|
|
568
|
+
| **Key Derivation and Wrapping** | 12 | 12 | 0 | ✅ Passed |
|
|
569
|
+
| **OOB Verification Codes** | 10 | 10 | 0 | ✅ Passed |
|
|
570
|
+
| **Key Transparency Log** | 8 | 8 | 0 | ✅ Passed |
|
|
571
|
+
| **Device Registry** | 5 | 5 | 0 | ✅ Passed |
|
|
572
|
+
| **Adversarial & Stress Integration Suites** | 8 | 8 | 0 | ✅ Passed |
|
|
573
|
+
| **Others** | 109 | 109 | 0 | ✅ Passed |
|
|
574
|
+
| **Total** | **219** | **219** | **0** | **✅ All Tests Passed** |
|
|
575
|
+
|
|
576
|
+
This includes advanced stress tests covering network chaos and out-of-order recovery, concurrent PCS ratchet updates and transactional state rollbacks, sealed sender byte malleability (verifying immunity to bit-flips across all packet bytes), and unwinding panic memory zeroization checks.
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## Performance Benchmarks
|
|
581
|
+
|
|
582
|
+
Vollcrypt Messages includes a dedicated high-performance benchmarking suite in Rust to measure the raw execution speed and throughput of the cryptographic core.
|
|
583
|
+
|
|
584
|
+
### Running the Benchmarks
|
|
585
|
+
To run the performance benchmarks:
|
|
586
|
+
```bash
|
|
587
|
+
cargo run --manifest-path vollcrypt-messages/core/Cargo.toml --release --bin perf
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
*Note: For maximum performance on x86_64 CPUs, ensure you build with hardware AES-NI acceleration enabled:*
|
|
591
|
+
```bash
|
|
592
|
+
RUSTFLAGS="-C target-cpu=native" cargo run --manifest-path vollcrypt-messages/core/Cargo.toml --release --bin perf
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
#### Automated Hardware & Resource Monitoring
|
|
596
|
+
We provide an automated PowerShell runner script ([benchmark_runner.ps1](file:///c:/Users/iTopya/Desktop/Project/vollcrypt/vollcrypt-messages/core/benchmark_runner.ps1)) that compiles the benchmark binary under release mode with AES-NI acceleration, collects your hardware specifications, tracks real-time CPU/RAM/GPU/Disk utilization, and formats everything into a markdown report.
|
|
597
|
+
|
|
598
|
+
To run this automated script on Windows:
|
|
599
|
+
```powershell
|
|
600
|
+
powershell -ExecutionPolicy Bypass -File vollcrypt-messages/core/benchmark_runner.ps1
|
|
601
|
+
```
|
|
602
|
+
The script will run the benchmarks, track resource usage, and generate a new [performance_report_optimized.md](file:///c:/Users/iTopya/Desktop/Project/vollcrypt/vollcrypt-messages/core/performance_report_optimized.md) inside `vollcrypt-messages/core/`.
|
|
603
|
+
|
|
604
|
+
### Reference Benchmark Figures
|
|
605
|
+
|
|
606
|
+
*The following values represent typical execution speeds measured under a Zero-Allocation architecture utilizing native hardware AES-NI acceleration on standard modern hardware (e.g. Intel Core i7 / AMD Ryzen 5 class CPU):*
|
|
607
|
+
|
|
608
|
+
#### Symmetric Throughput (AES-256-GCM)
|
|
609
|
+
| Operation | Data Payload Size | Throughput (Pure Software) | Throughput (Hardware AES-NI) |
|
|
610
|
+
| :--- | :---: | :---: | :---: |
|
|
611
|
+
| **AES-GCM Encryption** | 64 KB | ~300 MB/s | ~9,200 MB/s |
|
|
612
|
+
| **AES-GCM Decryption** | 64 KB | ~295 MB/s | ~10,200 MB/s |
|
|
613
|
+
| **AES-GCM Encryption** | 1 MB | ~290 MB/s | ~9,300 MB/s |
|
|
614
|
+
| **AES-GCM Decryption** | 1 MB | ~300 MB/s | ~10,100 MB/s |
|
|
615
|
+
| **AES-GCM Chunked (1MB Chunks)** | 16 MB | ~240 MB/s | ~5,200 MB/s |
|
|
616
|
+
|
|
617
|
+
#### Cryptographic Primitives & Handshakes
|
|
618
|
+
| Primitive | Operation / Scenario | Execution Speed (ops/second) |
|
|
619
|
+
| :--- | :---: | :---: |
|
|
620
|
+
| **HKDF-SHA256** | Key Expansion (32-byte key) | ~850,000 ops/s |
|
|
621
|
+
| **PBKDF2-HMAC-SHA256** | Password Hashing (600,000 iterations) | ~11.6 ops/s (Single thread) |
|
|
622
|
+
| **ML-KEM-768** | Encapsulation (Client Handshake) | ~8,300 ops/s |
|
|
623
|
+
| **ML-KEM-768** | Decapsulation (Recipient Handshake) | ~6,500 ops/s |
|
|
624
|
+
| **Sealed Sender** | Ephemeral DH Seal (Alice) | ~16,600 ops/s |
|
|
625
|
+
| **Sealed Sender** | Decryption & Parse Unseal (Bob) | ~22,400 ops/s |
|
|
626
|
+
| **PCS Ratchet** | Ephemeral X25519 Key Pair Gen | ~64,600 ops/s |
|
|
627
|
+
| **PCS Ratchet** | Session KDF Update (Step Computation) | ~21,800 ops/s |
|
|
628
|
+
| **Key Verification** | Out-of-band Numeric/Emoji Code Gen | ~473,000 ops/s |
|
|
629
|
+
| **Key Transparency** | 100-entry Chain Verification | ~300 ops/s |
|
|
630
|
+
|
|
631
|
+
#### Asymmetric Identity Primitives (Ed25519 & BIP-39)
|
|
632
|
+
| Primitive | Operation / Scenario | Execution Speed (ops/second) |
|
|
633
|
+
| :--- | :---: | :---: |
|
|
634
|
+
| **Ed25519 Signing** | Sign 1KB Payload | ~28,400 ops/s |
|
|
635
|
+
| **Ed25519 Verification** | Verify 1KB Signature | ~30,600 ops/s |
|
|
636
|
+
| **Ed25519 Signing** | Sign 1MB Payload | ~410 ops/s |
|
|
637
|
+
| **Ed25519 Verification** | Verify 1MB Signature | ~820 ops/s |
|
|
638
|
+
| **BIP-39 Mnemonic** | 24-word Mnemonic to 64-byte Seed | ~1,090 ops/s |
|
|
639
|
+
|
|
640
|
+
#### Multi-threaded Concurrency Throughput
|
|
641
|
+
| Scenario | Execution Context | Aggregate Throughput |
|
|
642
|
+
| :--- | :--- | :---: |
|
|
643
|
+
| **Multi-threaded Handshake Scaling** | Concurrent ML-KEM Encaps + Unseal (12 threads) | ~88,200 ops/s |
|
|
644
|
+
|
|
645
|
+
#### Memory State Lookup Latencies (Replay Prevention Store)
|
|
646
|
+
| Operation | Target Hash State | Average Latency |
|
|
647
|
+
| :--- | :---: | :---: |
|
|
648
|
+
| **Hash Lookup (Hit)** | Populated with 100,000 hashes | ~91.64 ns |
|
|
649
|
+
| **Hash Lookup (Miss)** | Populated with 100,000 hashes | ~36.40 ns |
|
|
650
|
+
| **Hash Insertion** | Populated with 100,000 hashes | ~109.78 ns |
|
|
651
|
+
|
|
652
|
+
### Measured Performance on Test Device
|
|
653
|
+
|
|
654
|
+
The actual performance benchmarks measured on the test device, along with the device's hardware specs and real-time resource utilization, are recorded in the [Performance Report](file:///c:/Users/iTopya/Desktop/Project/vollcrypt/vollcrypt-messages/core/performance_report_optimized.md).
|
|
655
|
+
|
|
656
|
+
#### System Specifications
|
|
657
|
+
* **Operating System (OS):** Microsoft Windows 11 Home
|
|
658
|
+
* **Processor (CPU):** AMD Ryzen 5 7500F 6-Core Processor
|
|
659
|
+
* **System Memory (RAM):** 15.62 GB
|
|
660
|
+
* **Graphics Controller (GPU):** NVIDIA GeForce GTX 1660 SUPER
|
|
661
|
+
* **Disk Volumes:**
|
|
662
|
+
* C: 465.1 GB total, 40.1 GB free
|
|
663
|
+
* D: 931.5 GB total, 733.8 GB free
|
|
664
|
+
|
|
665
|
+
#### Executed Benchmark Metrics (with Hardware AES-NI & Zero-Allocation)
|
|
666
|
+
* **AES-GCM-RAW (64 KB)**: Encrypt ~9238.73 MB/s | Decrypt ~10219.26 MB/s
|
|
667
|
+
* **AES-GCM-RAW (1 MB)**: Encrypt ~9324.03 MB/s | Decrypt ~10175.09 MB/s
|
|
668
|
+
* **AES-GCM-RAW (16 MB)**: Encrypt ~6814.46 MB/s | Decrypt ~7829.51 MB/s
|
|
669
|
+
* **AES-GCM (1 KB)**: Encrypt ~4629.74 MB/s | Decrypt ~6033.75 MB/s
|
|
670
|
+
* **AES-GCM (64 KB)**: Encrypt ~8170.76 MB/s | Decrypt ~6152.79 MB/s
|
|
671
|
+
* **AES-GCM (1 MB)**: Encrypt ~2940.28 MB/s | Decrypt ~10270.89 MB/s
|
|
672
|
+
* **AES-GCM (16 MB)**: Encrypt ~4413.80 MB/s | Decrypt ~7205.84 MB/s
|
|
673
|
+
* **AES-GCM-CHUNKED (16 MB payload, 1 MB chunks)**: Encrypt ~5242.40 MB/s | Decrypt ~5857.67 MB/s
|
|
674
|
+
* **AES-GCM-CHUNKED (64 MB payload, 1 MB chunks)**: Encrypt ~4667.03 MB/s | Decrypt ~4630.15 MB/s
|
|
675
|
+
* **HKDF-SHA256**: ~851,788.76 ops/s
|
|
676
|
+
* **PBKDF2-HMAC-SHA256 (600k iterations)**: ~11.66 ops/s
|
|
677
|
+
* **ML-KEM-768 Encapsulation**: ~8,357.29 ops/s
|
|
678
|
+
* **ML-KEM-768 Decapsulation**: ~6,582.30 ops/s
|
|
679
|
+
* **Sealed Sender Seal**: ~16,660.06 ops/s
|
|
680
|
+
* **Sealed Sender Unseal**: ~22,491.93 ops/s
|
|
681
|
+
* **PCS Ratchet Keypair Gen**: ~64,686.40 ops/s
|
|
682
|
+
* **PCS Ratchet Step Computation**: ~21,814.25 ops/s
|
|
683
|
+
* **Key Verification Code Gen**: ~473,126.42 ops/s
|
|
684
|
+
* **Key Transparency Log (100 entries chain verification)**: ~304.31 ops/s
|
|
685
|
+
* **Ed25519 Signing (1KB)**: ~28,494.74 ops/s
|
|
686
|
+
* **Ed25519 Verification (1KB)**: ~30,631.25 ops/s
|
|
687
|
+
* **Ed25519 Signing (1MB)**: ~414.84 ops/s
|
|
688
|
+
* **Ed25519 Verification (1MB)**: ~829.89 ops/s
|
|
689
|
+
* **BIP-39 Mnemonic to Seed**: ~1098.39 ops/s
|
|
690
|
+
* **Multi-threaded Handshake Scaling (12 threads)**: ~88,248.92 aggregate ops/s
|
|
691
|
+
* **Replay Store Lookup (Hit)**: ~91.64 ns
|
|
692
|
+
* **Replay Store Lookup (Miss)**: ~36.40 ns
|
|
693
|
+
* **Replay Store Insertion**: ~109.78 ns
|
|
694
|
+
|
|
695
|
+
#### Resource Utilization during run
|
|
696
|
+
* **Total Test Duration:** 20.67 seconds
|
|
697
|
+
* **System CPU Utilization:** Min 9% | Max 100% | Avg 36.6%
|
|
698
|
+
* **Memory Utilization (RAM):** Min 36.4% | Max 40.3% | Avg 37.9%
|
|
699
|
+
* **Graphics Card Utilization (GPU):** Min 4% | Max 6% | Avg 5.1%
|
|
700
|
+
* **Disk Read Speed:** Max 10.3 MB/s | Avg 1.29 MB/s
|
|
701
|
+
* **Disk Write Speed:** Max 49.29 MB/s | Avg 6.94 MB/s
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
|