@cello-protocol/crypto 0.0.2

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.
Files changed (49) hide show
  1. package/dist/checkpoint.d.ts +52 -0
  2. package/dist/checkpoint.d.ts.map +1 -0
  3. package/dist/checkpoint.js +70 -0
  4. package/dist/checkpoint.js.map +1 -0
  5. package/dist/ed25519.d.ts +25 -0
  6. package/dist/ed25519.d.ts.map +1 -0
  7. package/dist/ed25519.js +120 -0
  8. package/dist/ed25519.js.map +1 -0
  9. package/dist/frost/frost-threshold-signer.d.ts +178 -0
  10. package/dist/frost/frost-threshold-signer.d.ts.map +1 -0
  11. package/dist/frost/frost-threshold-signer.js +478 -0
  12. package/dist/frost/frost-threshold-signer.js.map +1 -0
  13. package/dist/frost/index.d.ts +23 -0
  14. package/dist/frost/index.d.ts.map +1 -0
  15. package/dist/frost/index.js +22 -0
  16. package/dist/frost/index.js.map +1 -0
  17. package/dist/frost/stubs.d.ts +82 -0
  18. package/dist/frost/stubs.d.ts.map +1 -0
  19. package/dist/frost/stubs.js +157 -0
  20. package/dist/frost/stubs.js.map +1 -0
  21. package/dist/frost/types.d.ts +173 -0
  22. package/dist/frost/types.d.ts.map +1 -0
  23. package/dist/frost/types.js +21 -0
  24. package/dist/frost/types.js.map +1 -0
  25. package/dist/hashing.d.ts +17 -0
  26. package/dist/hashing.d.ts.map +1 -0
  27. package/dist/hashing.js +50 -0
  28. package/dist/hashing.js.map +1 -0
  29. package/dist/index.d.ts +14 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +14 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/merkle.d.ts +162 -0
  34. package/dist/merkle.d.ts.map +1 -0
  35. package/dist/merkle.js +240 -0
  36. package/dist/merkle.js.map +1 -0
  37. package/dist/ml-dsa.d.ts +100 -0
  38. package/dist/ml-dsa.d.ts.map +1 -0
  39. package/dist/ml-dsa.js +257 -0
  40. package/dist/ml-dsa.js.map +1 -0
  41. package/dist/relay-registration.d.ts +62 -0
  42. package/dist/relay-registration.d.ts.map +1 -0
  43. package/dist/relay-registration.js +87 -0
  44. package/dist/relay-registration.js.map +1 -0
  45. package/dist/types.d.ts +11 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +2 -0
  48. package/dist/types.js.map +1 -0
  49. package/package.json +49 -0
package/dist/merkle.js ADDED
@@ -0,0 +1,240 @@
1
+ /**
2
+ * RFC 6962 Merkle Tree Primitives
3
+ *
4
+ * PSEUDOCODE (Phase P)
5
+ * ====================
6
+ * References:
7
+ * RFC 6962 §2.1 — Merkle Hash Trees: construction
8
+ * RFC 6962 §2.1.1 — Merkle Audit Paths (inclusion proofs)
9
+ * FIPS 180-4 — SHA-256 specification
10
+ *
11
+ * --- build(leaves: Uint8Array[]) ---
12
+ * if leaves is empty:
13
+ * return SHA-256("") // RFC 6962 §2.1: D[0] = {}
14
+ * level := [leafHash(l) for l in leaves] // SHA-256(0x00 || l)
15
+ * while level.length > 1:
16
+ * next := []
17
+ * for i in 0..level.length step 2:
18
+ * if i+1 < level.length:
19
+ * next.push(nodeHash(level[i], level[i+1])) // SHA-256(0x01 || left || right)
20
+ * else:
21
+ * next.push(level[i]) // promote odd node — RFC 6962 §2.1: left-balanced
22
+ * level := next
23
+ * return level[0] // root
24
+ *
25
+ * --- inclusionProof(tree, index) ---
26
+ * // RFC 6962 §2.1.1: PATH(m, D[n]) = [] if n=1
27
+ * // otherwise siblings from leaf level up to root
28
+ * level := tree.levelHashes[0] // leaf hashes
29
+ * proof := []
30
+ * idx := index
31
+ * while level.length > 1:
32
+ * sibling := idx XOR 1 // flips last bit: 0→1 (right sibling), 1→0 (left sibling)
33
+ * if sibling < level.length:
34
+ * proof.push(level[sibling])
35
+ * // else: odd node was promoted — no sibling hash in proof
36
+ * next := ... (pair-and-promote)
37
+ * idx := idx >> 1
38
+ * level := next
39
+ * return proof
40
+ *
41
+ * --- verify(leafHash, index, treeSize, proof, expectedRoot) ---
42
+ * if treeSize == 0 or index >= treeSize: return false
43
+ * if treeSize == 1 and proof.empty: return leafHash == expectedRoot
44
+ * cur := leafHash
45
+ * idx := index; sz := treeSize; pi := 0
46
+ * while sz > 1:
47
+ * if idx is last at this level AND idx is even (promoted, no sibling):
48
+ * // cur carries up unchanged
49
+ * else:
50
+ * if pi >= proof.length: return false
51
+ * if proof[pi].length != 32: return false // AC-008: 31-byte sibling
52
+ * if idx is odd: cur := nodeHash(proof[pi], cur) // sibling is on the left
53
+ * else: cur := nodeHash(cur, proof[pi]) // sibling is on the right
54
+ * pi++
55
+ * idx := idx >> 1
56
+ * sz := ceil(sz / 2)
57
+ * if pi != proof.length: return false // wrong proof length (extra elements)
58
+ * return cur == expectedRoot
59
+ *
60
+ * --- edge cases ---
61
+ * index >= treeSize → false, no throw
62
+ * wrong proof length → false, no throw
63
+ * 31-byte sibling hash → false, no throw
64
+ * empty tree → SHA-256("") per RFC 6962 §2.1
65
+ *
66
+ * --- second-preimage protection (SI-001) ---
67
+ * Leaves are hashed as SHA-256(0x00 || data) — the 0x00 prefix ensures a crafted
68
+ * leaf payload that begins with 0x01 cannot collide with an internal nodeHash,
69
+ * because nodeHash uses 0x01 prefix on the already-hashed children, not the raw data.
70
+ */
71
+ import { msgLeafHash, ctrlLeafHash, nodeHash, hash } from "./hashing.js";
72
+ /**
73
+ * Build a left-balanced Merkle tree from an ordered list of leaf inputs.
74
+ *
75
+ * Per RFC 6962 §2.1:
76
+ * - "msg" leaves: SHA-256(0x00 || data) using msgLeafHash from hashing.ts
77
+ * - "ctrl" leaves: SHA-256(0x02 || data) using ctrlLeafHash from hashing.ts
78
+ * - "hash" leaves: data used as-is (caller pre-computed the leaf hash)
79
+ * - Internal nodes: SHA-256(0x01 || left || right) using nodeHash from hashing.ts
80
+ * - Odd nodes at each level are promoted unchanged (not duplicated)
81
+ * - Empty tree root = SHA-256("") (SHA-256 of empty byte string)
82
+ *
83
+ * @param leaves - Leaf inputs with explicit kind for correct prefix application.
84
+ * @returns MerkleTree with all level hashes stored for O(log n) proof generation.
85
+ */
86
+ export function buildMerkleTree(leaves) {
87
+ if (leaves.length === 0) {
88
+ return { size: 0, levelHashes: [] };
89
+ }
90
+ const levels = [];
91
+ let current = leaves.map((l) => {
92
+ if (l.kind === "ctrl")
93
+ return ctrlLeafHash(l.data);
94
+ if (l.kind === "hash")
95
+ return l.data;
96
+ return msgLeafHash(l.data);
97
+ });
98
+ levels.push(current);
99
+ while (current.length > 1) {
100
+ const next = [];
101
+ for (let i = 0; i < current.length; i += 2) {
102
+ if (i + 1 < current.length) {
103
+ next.push(nodeHash(current[i], current[i + 1]));
104
+ }
105
+ else {
106
+ // Promote the odd node unchanged (RFC 6962 §2.1 — left-balanced)
107
+ next.push(current[i]);
108
+ }
109
+ }
110
+ levels.push(next);
111
+ current = next;
112
+ }
113
+ return { size: leaves.length, levelHashes: levels };
114
+ }
115
+ /**
116
+ * Return the Merkle root of a built tree.
117
+ *
118
+ * Per RFC 6962 §2.1:
119
+ * - Empty tree → SHA-256("") (SHA-256 of empty byte string)
120
+ * - Otherwise → the single hash at the top level of levelHashes
121
+ *
122
+ * @param tree - A MerkleTree returned by buildMerkleTree.
123
+ * @returns 32-byte root hash.
124
+ */
125
+ export function merkleRoot(tree) {
126
+ if (tree.size === 0) {
127
+ return hash(new Uint8Array(0));
128
+ }
129
+ const top = tree.levelHashes[tree.levelHashes.length - 1];
130
+ return top[0];
131
+ }
132
+ /**
133
+ * Produce an RFC 6962 §2.1.1 inclusion proof for leaf at index.
134
+ *
135
+ * The proof is an ordered list of sibling hashes from the leaf level to the root.
136
+ * For each level, the sibling of the current node is included. Promoted (odd, last)
137
+ * nodes have no sibling at their level, so no hash is added.
138
+ *
139
+ * @param tree - A MerkleTree returned by buildMerkleTree.
140
+ * @param index - Zero-based index of the target leaf.
141
+ * @returns Array of 32-byte sibling hashes (may be empty for a single-leaf tree).
142
+ * @throws If index is out of range.
143
+ */
144
+ export function inclusionProof(tree, index) {
145
+ if (tree.size === 0 || index >= tree.size) {
146
+ throw new RangeError(`inclusionProof: index ${index} out of range for tree of size ${tree.size}`);
147
+ }
148
+ const proof = [];
149
+ let idx = index;
150
+ for (let level = 0; level < tree.levelHashes.length - 1; level++) {
151
+ const row = tree.levelHashes[level];
152
+ // Sibling index: XOR with 1 flips last bit (0→1 right sibling, 1→0 left sibling)
153
+ const siblingIdx = idx ^ 1;
154
+ if (siblingIdx < row.length) {
155
+ proof.push(row[siblingIdx]);
156
+ }
157
+ // If no sibling exists, this node is promoted (odd last node) — nothing added
158
+ idx = idx >> 1;
159
+ }
160
+ return proof;
161
+ }
162
+ /**
163
+ * Verify an RFC 6962 §2.1.1 inclusion proof.
164
+ *
165
+ * Reconstructs the root by traversing the proof from leaf to root and compares
166
+ * byte-for-byte to expectedRoot. Returns false (never throws) for all invalid inputs:
167
+ * - index out of range
168
+ * - wrong proof length
169
+ * - any sibling hash not exactly 32 bytes
170
+ * - reconstructed root doesn't match expectedRoot
171
+ *
172
+ * @param leafHash - Pre-computed leaf hash (SHA-256(0x00 || data)).
173
+ * @param index - Zero-based index of the leaf in the tree.
174
+ * @param treeSize - Total number of leaves in the tree.
175
+ * @param proof - Ordered sibling hashes from inclusionProof.
176
+ * @param expectedRoot - The expected 32-byte Merkle root.
177
+ * @returns true iff the proof is valid for the given leaf and root.
178
+ */
179
+ export function verifyInclusion(leafHash, index, treeSize, proof, expectedRoot) {
180
+ // AC-008: malformed leafHash — must be exactly 32 bytes
181
+ if (leafHash.length !== 32)
182
+ return false;
183
+ // AC-008: index out of range
184
+ if (treeSize === 0 || index >= treeSize)
185
+ return false;
186
+ // Single-leaf tree: root IS the leaf hash, proof must be empty
187
+ if (treeSize === 1) {
188
+ if (proof.length !== 0)
189
+ return false;
190
+ return constantTimeEqual(leafHash, expectedRoot);
191
+ }
192
+ // Validate all sibling hashes up front (AC-008: 31-byte sibling)
193
+ for (const sibling of proof) {
194
+ if (sibling.length !== 32)
195
+ return false;
196
+ }
197
+ let cur = leafHash;
198
+ let idx = index;
199
+ let sz = treeSize;
200
+ let proofIdx = 0;
201
+ while (sz > 1) {
202
+ const isLastAndOdd = idx === sz - 1 && idx % 2 === 0;
203
+ if (isLastAndOdd) {
204
+ // This node is promoted (odd last node at this level) — no sibling consumed
205
+ }
206
+ else {
207
+ // Expect a sibling from the proof
208
+ if (proofIdx >= proof.length)
209
+ return false;
210
+ const sibling = proof[proofIdx++];
211
+ if (idx % 2 === 1) {
212
+ // Current node is right child — sibling is to the left
213
+ cur = nodeHash(sibling, cur);
214
+ }
215
+ else {
216
+ // Current node is left child — sibling is to the right
217
+ cur = nodeHash(cur, sibling);
218
+ }
219
+ }
220
+ idx = idx >> 1;
221
+ sz = Math.ceil(sz / 2);
222
+ }
223
+ // AC-008: wrong proof length (extra elements remaining)
224
+ if (proofIdx !== proof.length)
225
+ return false;
226
+ return constantTimeEqual(cur, expectedRoot);
227
+ }
228
+ /**
229
+ * Constant-time byte array comparison to prevent timing side-channels.
230
+ */
231
+ function constantTimeEqual(a, b) {
232
+ if (a.length !== b.length)
233
+ return false;
234
+ let diff = 0;
235
+ for (let i = 0; i < a.length; i++) {
236
+ diff |= a[i] ^ b[i];
237
+ }
238
+ return diff === 0;
239
+ }
240
+ //# sourceMappingURL=merkle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.js","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @cello-protocol/crypto — ML-DSA-44 signing primitives (CELLO-CRYPTO-004)
3
+ *
4
+ * Phase P — Pseudocode (FIPS 204 / CRYSTALS-Dilithium)
5
+ * ────────────────────────────────────────────────────
6
+ * Implements ML-DSA-44 as defined in NIST FIPS 204
7
+ * (https://csrc.nist.gov/pubs/fips/204/final).
8
+ * Parameter set ML-DSA-44 (security level 2, 128-bit post-quantum security):
9
+ * public key = 1312 bytes
10
+ * secret key = 2560 bytes
11
+ * signature = 2420 bytes
12
+ *
13
+ * Library: @oqs/liboqs-js (WASM bindings to the Open Quantum Safe liboqs C library)
14
+ * API (note argument order in liboqs-js):
15
+ * createMLDSA44() → Promise<MLDSA44 instance>
16
+ * instance.generateKeyPair() → { publicKey: Uint8Array, secretKey: Uint8Array }
17
+ * instance.sign(message, secretKey) → Uint8Array (2420 bytes)
18
+ * instance.verify(message, signature, publicKey) → boolean
19
+ *
20
+ * Design:
21
+ * - A module-level singleton holds the WASM instance (loaded once, reused).
22
+ * - mlDsaKeygen() returns an InMemoryMlDsaKeyProvider wrapping the keypair.
23
+ * - mlDsaSign(secretKey, message) — free stateless signing function.
24
+ * - mlDsaVerify(publicKey, message, signature) — free stateless verification;
25
+ * catches LibOQSValidationError for wrong-size inputs and returns false.
26
+ * - Secret key never leaves the provider boundary; private fields enforce containment.
27
+ * - FileMlDsaKeyProvider persists keypair atomically (write-to-tmp + rename, 0o600).
28
+ *
29
+ * SI-003: parameter set is pinned to ML-DSA-44. No runtime selection is possible.
30
+ */
31
+ /** 1312-byte ML-DSA-44 public key */
32
+ export type MlDsaPublicKey = Uint8Array;
33
+ /** 2420-byte ML-DSA-44 signature */
34
+ export type MlDsaSignature = Uint8Array;
35
+ /** ML-DSA-44 keypair produced by key generation */
36
+ export interface MlDsaKeyPair {
37
+ publicKey: MlDsaPublicKey;
38
+ secretKey: Uint8Array;
39
+ }
40
+ /** Provider abstraction: holds secret key in private storage; exposes only public ops */
41
+ export interface MlDsaKeyProvider {
42
+ getPublicKey(): Promise<MlDsaPublicKey>;
43
+ sign(message: Uint8Array): Promise<MlDsaSignature>;
44
+ }
45
+ declare const INSPECT: unique symbol;
46
+ export declare class InMemoryMlDsaKeyProvider implements MlDsaKeyProvider {
47
+ #private;
48
+ constructor(publicKey: Uint8Array, secretKey: Uint8Array);
49
+ getPublicKey(): Promise<MlDsaPublicKey>;
50
+ sign(message: Uint8Array): Promise<MlDsaSignature>;
51
+ toJSON(): Record<string, string>;
52
+ toString(): string;
53
+ [INSPECT](): string;
54
+ }
55
+ export declare class FileMlDsaKeyProvider implements MlDsaKeyProvider {
56
+ #private;
57
+ private constructor();
58
+ /**
59
+ * Load (or generate) a key file at the given path.
60
+ *
61
+ * - No file → generate fresh keypair, write atomically (write-to-tmp + rename), 0o600
62
+ * - File exists and valid → load and return
63
+ * - File exists but corrupt → throw { reason: 'ml_dsa_key_file_corrupt' }, never overwrite
64
+ */
65
+ static load(path: string): Promise<FileMlDsaKeyProvider>;
66
+ /** Parse and validate a raw key file buffer. Throws on corrupt data. */
67
+ private static _parseFile;
68
+ getPublicKey(): Promise<MlDsaPublicKey>;
69
+ sign(message: Uint8Array): Promise<MlDsaSignature>;
70
+ toJSON(): Record<string, string>;
71
+ toString(): string;
72
+ [INSPECT](): string;
73
+ }
74
+ /**
75
+ * Generate a new ML-DSA-44 keypair and return an InMemoryMlDsaKeyProvider.
76
+ * SI-003: parameter set is pinned to ML-DSA-44 — no selection argument.
77
+ */
78
+ export declare function mlDsaKeygen(): Promise<InMemoryMlDsaKeyProvider>;
79
+ /**
80
+ * Sign a message with an ML-DSA-44 secret key.
81
+ * Returns a 2420-byte signature.
82
+ *
83
+ * Note: mlDsaSign is synchronous-looking but uses the cached WASM instance.
84
+ * In practice the WASM instance must already be loaded (call mlDsaKeygen first).
85
+ * If not loaded, throws synchronously — callers should prefer provider.sign().
86
+ */
87
+ export declare function mlDsaSign(secretKey: Uint8Array, message: Uint8Array): Uint8Array;
88
+ /**
89
+ * Verify an ML-DSA-44 signature.
90
+ * Returns false (never throws) for any invalid input including wrong-size keys.
91
+ * SI-003: only ML-DSA-44 is supported.
92
+ */
93
+ export declare function mlDsaVerify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
94
+ /**
95
+ * Ensure the WASM instance is loaded. Call this before using mlDsaSign/mlDsaVerify
96
+ * as free functions if you have not called mlDsaKeygen() yet.
97
+ */
98
+ export declare function mlDsaEnsureLoaded(): Promise<void>;
99
+ export {};
100
+ //# sourceMappingURL=ml-dsa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ml-dsa.d.ts","sourceRoot":"","sources":["../src/ml-dsa.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAOH,qCAAqC;AACrC,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC;AAExC,oCAAoC;AACpC,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC;AAExC,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,UAAU,CAAC;CACvB;AAED,yFAAyF;AACzF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACpD;AAgDD,QAAA,MAAM,OAAO,eAA2C,CAAC;AAIzD,qBAAa,wBAAyB,YAAW,gBAAgB;;gBAInD,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU;IAYlD,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC;IAKvC,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;IAUxD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOhC,QAAQ,IAAI,MAAM;IAIlB,CAAC,OAAO,CAAC,IAAI,MAAM;CAGpB;AAID,qBAAa,oBAAqB,YAAW,gBAAgB;;IAG3D,OAAO;IAIP;;;;;;OAMG;WACU,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAoD9D,wEAAwE;IACxE,OAAO,CAAC,MAAM,CAAC,UAAU;IA+BnB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC;IAIvC,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;IAKxD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOhC,QAAQ,IAAI,MAAM;IAIlB,CAAC,OAAO,CAAC,IAAI,MAAM;CAGpB;AAID;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAIrE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,CAKhF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,UAAU,EACrB,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,UAAU,GACpB,OAAO,CAUT;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvD"}
package/dist/ml-dsa.js ADDED
@@ -0,0 +1,257 @@
1
+ /**
2
+ * @cello-protocol/crypto — ML-DSA-44 signing primitives (CELLO-CRYPTO-004)
3
+ *
4
+ * Phase P — Pseudocode (FIPS 204 / CRYSTALS-Dilithium)
5
+ * ────────────────────────────────────────────────────
6
+ * Implements ML-DSA-44 as defined in NIST FIPS 204
7
+ * (https://csrc.nist.gov/pubs/fips/204/final).
8
+ * Parameter set ML-DSA-44 (security level 2, 128-bit post-quantum security):
9
+ * public key = 1312 bytes
10
+ * secret key = 2560 bytes
11
+ * signature = 2420 bytes
12
+ *
13
+ * Library: @oqs/liboqs-js (WASM bindings to the Open Quantum Safe liboqs C library)
14
+ * API (note argument order in liboqs-js):
15
+ * createMLDSA44() → Promise<MLDSA44 instance>
16
+ * instance.generateKeyPair() → { publicKey: Uint8Array, secretKey: Uint8Array }
17
+ * instance.sign(message, secretKey) → Uint8Array (2420 bytes)
18
+ * instance.verify(message, signature, publicKey) → boolean
19
+ *
20
+ * Design:
21
+ * - A module-level singleton holds the WASM instance (loaded once, reused).
22
+ * - mlDsaKeygen() returns an InMemoryMlDsaKeyProvider wrapping the keypair.
23
+ * - mlDsaSign(secretKey, message) — free stateless signing function.
24
+ * - mlDsaVerify(publicKey, message, signature) — free stateless verification;
25
+ * catches LibOQSValidationError for wrong-size inputs and returns false.
26
+ * - Secret key never leaves the provider boundary; private fields enforce containment.
27
+ * - FileMlDsaKeyProvider persists keypair atomically (write-to-tmp + rename, 0o600).
28
+ *
29
+ * SI-003: parameter set is pinned to ML-DSA-44. No runtime selection is possible.
30
+ */
31
+ import { readFile, rename, mkdir, open as fsOpen } from "node:fs/promises";
32
+ import { dirname, join } from "node:path";
33
+ let _wasmPromise = null;
34
+ async function _loadWasm() {
35
+ // Dynamic import keeps liboqs-js out of the synchronous module graph.
36
+ // createMLDSA44 initialises and returns an ML-DSA-44 WASM context.
37
+ const { createMLDSA44 } = await import("@oqs/liboqs-js");
38
+ return createMLDSA44();
39
+ }
40
+ async function _getWasm() {
41
+ if (_wasmPromise === null) {
42
+ _wasmPromise = _loadWasm();
43
+ }
44
+ const instance = await _wasmPromise;
45
+ // Cache the resolved value so the synchronous mlDsaSign/mlDsaVerify free
46
+ // functions can read it without re-awaiting.
47
+ _wasmInstance = instance;
48
+ return instance;
49
+ }
50
+ // Populated after the first _getWasm() resolves. Synchronous free functions
51
+ // (mlDsaSign, mlDsaVerify) read this directly. Callers must ensure _getWasm()
52
+ // has been awaited (via mlDsaKeygen() or mlDsaEnsureLoaded()) before calling
53
+ // the synchronous free functions.
54
+ let _wasmInstance = null;
55
+ // ─── File format constants ───────────────────────────────────────────────────
56
+ // File layout: magic(5) + version(1) + publicKey(1312) + secretKey(2560) = 3878 bytes
57
+ const ML_DSA_FILE_MAGIC = new Uint8Array([0xce, 0x11, 0x0d, 0x53, 0x41]); // "CELLO_MLDSA"
58
+ const ML_DSA_FILE_VERSION = 1;
59
+ const ML_DSA_PK_BYTES = 1312;
60
+ const ML_DSA_SK_BYTES = 2560;
61
+ const ML_DSA_FILE_SIZE = ML_DSA_FILE_MAGIC.length + 1 + ML_DSA_PK_BYTES + ML_DSA_SK_BYTES;
62
+ // ─── Custom inspect symbol ───────────────────────────────────────────────────
63
+ const INSPECT = Symbol.for("nodejs.util.inspect.custom");
64
+ // ─── InMemoryMlDsaKeyProvider ────────────────────────────────────────────────
65
+ export class InMemoryMlDsaKeyProvider {
66
+ #publicKey;
67
+ #secretKey;
68
+ constructor(publicKey, secretKey) {
69
+ if (publicKey.length !== ML_DSA_PK_BYTES) {
70
+ throw new Error(`ML-DSA-44 public key must be ${ML_DSA_PK_BYTES} bytes, got ${publicKey.length}`);
71
+ }
72
+ if (secretKey.length !== ML_DSA_SK_BYTES) {
73
+ throw new Error(`ML-DSA-44 secret key must be ${ML_DSA_SK_BYTES} bytes, got ${secretKey.length}`);
74
+ }
75
+ // Defensive copies: ensure the internal state is not shared with caller buffers.
76
+ this.#publicKey = publicKey.slice();
77
+ this.#secretKey = secretKey.slice();
78
+ }
79
+ async getPublicKey() {
80
+ // Return a copy to prevent external mutation of the internal public key buffer.
81
+ return this.#publicKey.slice();
82
+ }
83
+ async sign(message) {
84
+ const wasm = await _getWasm();
85
+ // liboqs-js validates `message.constructor.name === 'Uint8Array'`, which fails for
86
+ // cross-realm Uint8Arrays (bytes from a compiled dep resolved in a different V8 context).
87
+ // new Uint8Array(message) copies the bytes into a fresh instance in the current realm.
88
+ const msg = new Uint8Array(message);
89
+ return wasm.sign(msg, this.#secretKey);
90
+ }
91
+ // SI-001: redacted representations — secret key must never appear in any of these
92
+ toJSON() {
93
+ return {
94
+ type: "InMemoryMlDsaKeyProvider",
95
+ publicKey: Buffer.from(this.#publicKey).toString("hex"),
96
+ };
97
+ }
98
+ toString() {
99
+ return `InMemoryMlDsaKeyProvider(pubkey=${Buffer.from(this.#publicKey).toString("hex")})`;
100
+ }
101
+ [INSPECT]() {
102
+ return this.toString();
103
+ }
104
+ }
105
+ // ─── FileMlDsaKeyProvider ────────────────────────────────────────────────────
106
+ export class FileMlDsaKeyProvider {
107
+ #inner;
108
+ constructor(inner) {
109
+ this.#inner = inner;
110
+ }
111
+ /**
112
+ * Load (or generate) a key file at the given path.
113
+ *
114
+ * - No file → generate fresh keypair, write atomically (write-to-tmp + rename), 0o600
115
+ * - File exists and valid → load and return
116
+ * - File exists but corrupt → throw { reason: 'ml_dsa_key_file_corrupt' }, never overwrite
117
+ */
118
+ static async load(path) {
119
+ let raw = null;
120
+ try {
121
+ raw = await readFile(path);
122
+ }
123
+ catch (err) {
124
+ const code = err.code;
125
+ if (code !== "ENOENT") {
126
+ throw {
127
+ reason: "ml_dsa_key_file_corrupt",
128
+ message: `cannot read ML-DSA key file: ${err.message}`,
129
+ };
130
+ }
131
+ // ENOENT → fall through to generation
132
+ }
133
+ if (raw !== null) {
134
+ return FileMlDsaKeyProvider._parseFile(raw);
135
+ }
136
+ // Generate and atomically write a new key file.
137
+ const wasm = await _getWasm();
138
+ const { publicKey, secretKey } = wasm.generateKeyPair();
139
+ const buf = Buffer.alloc(ML_DSA_FILE_SIZE);
140
+ let offset = 0;
141
+ ML_DSA_FILE_MAGIC.forEach((b, i) => { buf[i] = b; });
142
+ offset = ML_DSA_FILE_MAGIC.length;
143
+ buf[offset++] = ML_DSA_FILE_VERSION;
144
+ publicKey.forEach((b, i) => { buf[offset + i] = b; });
145
+ offset += ML_DSA_PK_BYTES;
146
+ secretKey.forEach((b, i) => { buf[offset + i] = b; });
147
+ const dir = dirname(path);
148
+ await mkdir(dir, { recursive: true });
149
+ const tmp = join(dir, `.cello-mldsa-key-tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`);
150
+ const fd = await fsOpen(tmp, "wx", 0o600);
151
+ try {
152
+ await fd.write(buf);
153
+ await fd.chmod(0o600);
154
+ }
155
+ finally {
156
+ await fd.close();
157
+ }
158
+ await rename(tmp, path);
159
+ return new FileMlDsaKeyProvider(new InMemoryMlDsaKeyProvider(publicKey, secretKey));
160
+ }
161
+ /** Parse and validate a raw key file buffer. Throws on corrupt data. */
162
+ static _parseFile(raw) {
163
+ if (raw.length !== ML_DSA_FILE_SIZE) {
164
+ throw {
165
+ reason: "ml_dsa_key_file_corrupt",
166
+ message: `ML-DSA key file has wrong length: expected ${ML_DSA_FILE_SIZE}, got ${raw.length}`,
167
+ };
168
+ }
169
+ for (let i = 0; i < ML_DSA_FILE_MAGIC.length; i++) {
170
+ if (raw[i] !== ML_DSA_FILE_MAGIC[i]) {
171
+ throw {
172
+ reason: "ml_dsa_key_file_corrupt",
173
+ message: "ML-DSA key file has invalid magic bytes",
174
+ };
175
+ }
176
+ }
177
+ if (raw[ML_DSA_FILE_MAGIC.length] !== ML_DSA_FILE_VERSION) {
178
+ throw {
179
+ reason: "ml_dsa_key_file_corrupt",
180
+ message: `ML-DSA key file has unsupported version: ${raw[ML_DSA_FILE_MAGIC.length]}`,
181
+ };
182
+ }
183
+ let offset = ML_DSA_FILE_MAGIC.length + 1;
184
+ const publicKey = new Uint8Array(raw.buffer, raw.byteOffset + offset, ML_DSA_PK_BYTES).slice();
185
+ offset += ML_DSA_PK_BYTES;
186
+ const secretKey = new Uint8Array(raw.buffer, raw.byteOffset + offset, ML_DSA_SK_BYTES).slice();
187
+ return new FileMlDsaKeyProvider(new InMemoryMlDsaKeyProvider(publicKey, secretKey));
188
+ }
189
+ async getPublicKey() {
190
+ return this.#inner.getPublicKey();
191
+ }
192
+ async sign(message) {
193
+ return this.#inner.sign(message);
194
+ }
195
+ // SI-001: redacted representations
196
+ toJSON() {
197
+ return {
198
+ type: "FileMlDsaKeyProvider",
199
+ publicKey: this.#inner.toJSON()["publicKey"],
200
+ };
201
+ }
202
+ toString() {
203
+ return `FileMlDsaKeyProvider(pubkey=${this.#inner.toJSON()["publicKey"]})`;
204
+ }
205
+ [INSPECT]() {
206
+ return this.toString();
207
+ }
208
+ }
209
+ // ─── Free functions ──────────────────────────────────────────────────────────
210
+ /**
211
+ * Generate a new ML-DSA-44 keypair and return an InMemoryMlDsaKeyProvider.
212
+ * SI-003: parameter set is pinned to ML-DSA-44 — no selection argument.
213
+ */
214
+ export async function mlDsaKeygen() {
215
+ const wasm = await _getWasm();
216
+ const { publicKey, secretKey } = wasm.generateKeyPair();
217
+ return new InMemoryMlDsaKeyProvider(publicKey, secretKey);
218
+ }
219
+ /**
220
+ * Sign a message with an ML-DSA-44 secret key.
221
+ * Returns a 2420-byte signature.
222
+ *
223
+ * Note: mlDsaSign is synchronous-looking but uses the cached WASM instance.
224
+ * In practice the WASM instance must already be loaded (call mlDsaKeygen first).
225
+ * If not loaded, throws synchronously — callers should prefer provider.sign().
226
+ */
227
+ export function mlDsaSign(secretKey, message) {
228
+ if (_wasmInstance === null) {
229
+ throw new Error("ML-DSA WASM not loaded — call mlDsaKeygen() or await mlDsaEnsureLoaded() first");
230
+ }
231
+ return _wasmInstance.sign(message, secretKey);
232
+ }
233
+ /**
234
+ * Verify an ML-DSA-44 signature.
235
+ * Returns false (never throws) for any invalid input including wrong-size keys.
236
+ * SI-003: only ML-DSA-44 is supported.
237
+ */
238
+ export function mlDsaVerify(publicKey, message, signature) {
239
+ if (_wasmInstance === null) {
240
+ return false;
241
+ }
242
+ try {
243
+ return _wasmInstance.verify(message, signature, publicKey);
244
+ }
245
+ catch {
246
+ // LibOQSValidationError for wrong-size keys/signatures → return false (AC-005, AC-006)
247
+ return false;
248
+ }
249
+ }
250
+ /**
251
+ * Ensure the WASM instance is loaded. Call this before using mlDsaSign/mlDsaVerify
252
+ * as free functions if you have not called mlDsaKeygen() yet.
253
+ */
254
+ export async function mlDsaEnsureLoaded() {
255
+ await _getWasm();
256
+ }
257
+ //# sourceMappingURL=ml-dsa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ml-dsa.js","sourceRoot":"","sources":["../src/ml-dsa.ts"],"names":[],"mappings":"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"}