@hippius/hcfs-client-wasm 0.1.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.
@@ -0,0 +1,209 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Opaque wrapper around a sensitive byte buffer.
6
+ *
7
+ * The buffer is stored in [`Zeroizing`] and scrubbed on drop (or when JS
8
+ * calls `free()`). Prefer passing `SecretBytes` to other WASM APIs rather
9
+ * than calling [`Self::expose`], since any `Uint8Array` copy on the JS
10
+ * side cannot be reliably zeroed.
11
+ *
12
+ * # Invariant
13
+ *
14
+ * The inner `Vec<u8>` is never mutated after construction. The handle
15
+ * constructs at exact capacity (no reallocation), which avoids the
16
+ * `Zeroize for Vec<u8>` pitfall where a realloc frees the old heap
17
+ * buffer without scrubbing it.
18
+ */
19
+ export class SecretBytes {
20
+ free(): void;
21
+ [Symbol.dispose](): void;
22
+ /**
23
+ * Copy the bytes out as a `Uint8Array`.
24
+ *
25
+ * The caller is responsible for zeroing the returned buffer when it
26
+ * is no longer needed. The internal copy inside this handle remains
27
+ * zeroized-on-drop.
28
+ *
29
+ * Note that wasm-bindgen's generated trampoline takes ownership of
30
+ * the returned `Vec<u8>` and drops it after marshaling to JS — that
31
+ * final drop is outside our control and does not scrub. To minimize
32
+ * the unscrubbed window, callers should process the returned
33
+ * `Uint8Array` immediately and call `fill(0)` on it when done.
34
+ */
35
+ expose(): Uint8Array;
36
+ /**
37
+ * Wrap a byte buffer in a zeroize-on-drop handle.
38
+ *
39
+ * Useful from JS when a caller already has key material (e.g.,
40
+ * previously derived and cached across workers) and wants to hand it
41
+ * back into a WASM decrypt call without going through `expose`.
42
+ */
43
+ constructor(bytes: Uint8Array);
44
+ /**
45
+ * Length of the underlying secret in bytes.
46
+ */
47
+ readonly length: number;
48
+ }
49
+
50
+ /**
51
+ * Opaque wrapper around a sensitive UTF-8 string (mnemonics, etc.).
52
+ *
53
+ * Internally stored as `Zeroizing<Vec<u8>>` — UTF-8 validated on
54
+ * construction, exposed on access. Using a `Vec<u8>` (rather than
55
+ * `String`) makes it harder to accidentally introduce mutation that
56
+ * would realloc and leak the old buffer.
57
+ *
58
+ * # Invariant
59
+ *
60
+ * The inner Vec is never mutated after construction. Any future change
61
+ * that mutates a `SecretString`'s inner bytes MUST ensure no
62
+ * reallocation occurs (reserve exact capacity up-front).
63
+ */
64
+ export class SecretString {
65
+ private constructor();
66
+ free(): void;
67
+ [Symbol.dispose](): void;
68
+ /**
69
+ * Copy the string out to JS.
70
+ *
71
+ * The returned JS string lives on the V8 heap and cannot be zeroed.
72
+ * Minimize retention: decode, act, discard. For the most
73
+ * security-conscious callers, prefer [`Self::expose_bytes`] and
74
+ * decode via `TextDecoder`, then `fill(0)` the underlying byte
75
+ * buffer before any copy is made.
76
+ *
77
+ * Inherent limitation: wasm-bindgen's generated trampoline takes
78
+ * ownership of the returned `String` and drops it after marshaling
79
+ * to the JS heap. That final drop is outside our control and does
80
+ * not scrub. The Rust-side window is a single function call frame.
81
+ */
82
+ expose(): string;
83
+ /**
84
+ * Copy the underlying UTF-8 bytes out as a `Uint8Array`.
85
+ *
86
+ * Prefer this over [`Self::expose`] when the caller wants the
87
+ * option to `fill(0)` the bytes in JS before they become an
88
+ * immutable JS string. Decode in JS with `new TextDecoder().decode(bytes)`.
89
+ */
90
+ expose_bytes(): Uint8Array;
91
+ /**
92
+ * Length of the underlying secret in bytes (UTF-8 byte length, not
93
+ * Unicode scalar count).
94
+ */
95
+ readonly length: number;
96
+ }
97
+
98
+ /**
99
+ * Derive a 32-byte key from a passphrase and salt using Argon2id.
100
+ *
101
+ * Exposed separately so the browser can perform the KDF step independently
102
+ * (e.g. to show a progress indicator while the KDF runs). Parameters are
103
+ * enforced against the OWASP 2023 minimum (see [`MIN_ARGON2_MEMORY_KIB`]).
104
+ */
105
+ export function argon2id_derive(passphrase: string, salt: Uint8Array, memory_kib: number, time_cost: number, parallelism: number): SecretBytes;
106
+
107
+ /**
108
+ * Decrypt a single HCFS file chunk using XChaCha20-Poly1305.
109
+ *
110
+ * The ciphertext includes the 16-byte Poly1305 auth tag appended at the end
111
+ * (same wire format as `hcfs-client` streaming encryption).
112
+ *
113
+ * - `key`: 32-byte encryption key (opaque handle)
114
+ * - `base_nonce`: 24-byte base nonce (from the file header)
115
+ * - `chunk_index`: 0-based chunk index (used to derive per-chunk nonce)
116
+ * - `ciphertext`: chunk ciphertext including the trailing 16-byte auth tag
117
+ *
118
+ * Returns the decrypted plaintext as a `Uint8Array`. On authentication
119
+ * failure the intermediate plaintext buffer is zeroized before the error
120
+ * returns.
121
+ */
122
+ export function decrypt_file_chunk(key: SecretBytes, base_nonce: Uint8Array, chunk_index: number, ciphertext: Uint8Array): Uint8Array;
123
+
124
+ /**
125
+ * Derive a 32-byte per-folder encryption key from a master mnemonic and label.
126
+ *
127
+ * Chain: master → seed → SHA256(seed[..32] || label) → folder mnemonic → folder seed[..32].
128
+ */
129
+ export function derive_file_key(master_mnemonic: string, label: string): SecretBytes;
130
+
131
+ /**
132
+ * Derive a folder-specific mnemonic from a master mnemonic and folder label.
133
+ *
134
+ * Algorithm: `SHA256(master_seed[..32] || label)` → 32-byte entropy → 24-word mnemonic.
135
+ */
136
+ export function derive_folder_mnemonic(master: string, label: string): SecretString;
137
+
138
+ /**
139
+ * Convert a BIP-39 mnemonic phrase to a 64-byte seed.
140
+ *
141
+ * Uses an empty passphrase for deterministic derivation (same as the
142
+ * native client). Returns a [`SecretBytes`] handle.
143
+ */
144
+ export function mnemonic_to_seed(phrase: string): SecretBytes;
145
+
146
+ /**
147
+ * Decrypt a sealed mnemonic blob using a passphrase.
148
+ *
149
+ * `blob_json` is the JSON string of the `SealedBlob` (same shape as returned
150
+ * by `GET /v1/mnemonic-blob`). `passphrase` is the user's passphrase.
151
+ * `expected_ss58` is the SS58 address the caller believes owns this blob —
152
+ * it is used as the AEAD associated data. If the blob was sealed under a
153
+ * different SS58, the AEAD tag check will fail, preventing blob-swap attacks.
154
+ *
155
+ * KDF parameters carried inside the blob are validated against the same
156
+ * OWASP floor as [`argon2id_derive`]; a server that advertises weak params
157
+ * is rejected rather than trusted.
158
+ *
159
+ * Returns the decrypted mnemonic phrase as a [`SecretString`] handle.
160
+ */
161
+ export function open_mnemonic_blob(blob_json: string, passphrase: string, expected_ss58: string): SecretString;
162
+
163
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
164
+
165
+ export interface InitOutput {
166
+ readonly memory: WebAssembly.Memory;
167
+ readonly __wbg_secretbytes_free: (a: number, b: number) => void;
168
+ readonly __wbg_secretstring_free: (a: number, b: number) => void;
169
+ readonly argon2id_derive: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
170
+ readonly decrypt_file_chunk: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
171
+ readonly derive_file_key: (a: number, b: number, c: number, d: number) => [number, number, number];
172
+ readonly derive_folder_mnemonic: (a: number, b: number, c: number, d: number) => [number, number, number];
173
+ readonly mnemonic_to_seed: (a: number, b: number) => [number, number, number];
174
+ readonly open_mnemonic_blob: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
175
+ readonly secretbytes_expose: (a: number) => [number, number];
176
+ readonly secretbytes_length: (a: number) => number;
177
+ readonly secretbytes_new: (a: number, b: number) => number;
178
+ readonly secretstring_expose: (a: number) => [number, number];
179
+ readonly secretstring_expose_bytes: (a: number) => [number, number];
180
+ readonly secretstring_length: (a: number) => number;
181
+ readonly __wbindgen_externrefs: WebAssembly.Table;
182
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
183
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
184
+ readonly __externref_table_dealloc: (a: number) => void;
185
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
186
+ readonly __wbindgen_start: () => void;
187
+ }
188
+
189
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
190
+
191
+ /**
192
+ * Instantiates the given `module`, which can either be bytes or
193
+ * a precompiled `WebAssembly.Module`.
194
+ *
195
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
196
+ *
197
+ * @returns {InitOutput}
198
+ */
199
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
200
+
201
+ /**
202
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
203
+ * for everything else, calls `WebAssembly.instantiate` directly.
204
+ *
205
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
206
+ *
207
+ * @returns {Promise<InitOutput>}
208
+ */
209
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
@@ -0,0 +1,545 @@
1
+ /* @ts-self-types="./hcfs_client_wasm.d.ts" */
2
+
3
+ /**
4
+ * Opaque wrapper around a sensitive byte buffer.
5
+ *
6
+ * The buffer is stored in [`Zeroizing`] and scrubbed on drop (or when JS
7
+ * calls `free()`). Prefer passing `SecretBytes` to other WASM APIs rather
8
+ * than calling [`Self::expose`], since any `Uint8Array` copy on the JS
9
+ * side cannot be reliably zeroed.
10
+ *
11
+ * # Invariant
12
+ *
13
+ * The inner `Vec<u8>` is never mutated after construction. The handle
14
+ * constructs at exact capacity (no reallocation), which avoids the
15
+ * `Zeroize for Vec<u8>` pitfall where a realloc frees the old heap
16
+ * buffer without scrubbing it.
17
+ */
18
+ export class SecretBytes {
19
+ static __wrap(ptr) {
20
+ ptr = ptr >>> 0;
21
+ const obj = Object.create(SecretBytes.prototype);
22
+ obj.__wbg_ptr = ptr;
23
+ SecretBytesFinalization.register(obj, obj.__wbg_ptr, obj);
24
+ return obj;
25
+ }
26
+ __destroy_into_raw() {
27
+ const ptr = this.__wbg_ptr;
28
+ this.__wbg_ptr = 0;
29
+ SecretBytesFinalization.unregister(this);
30
+ return ptr;
31
+ }
32
+ free() {
33
+ const ptr = this.__destroy_into_raw();
34
+ wasm.__wbg_secretbytes_free(ptr, 0);
35
+ }
36
+ /**
37
+ * Copy the bytes out as a `Uint8Array`.
38
+ *
39
+ * The caller is responsible for zeroing the returned buffer when it
40
+ * is no longer needed. The internal copy inside this handle remains
41
+ * zeroized-on-drop.
42
+ *
43
+ * Note that wasm-bindgen's generated trampoline takes ownership of
44
+ * the returned `Vec<u8>` and drops it after marshaling to JS — that
45
+ * final drop is outside our control and does not scrub. To minimize
46
+ * the unscrubbed window, callers should process the returned
47
+ * `Uint8Array` immediately and call `fill(0)` on it when done.
48
+ * @returns {Uint8Array}
49
+ */
50
+ expose() {
51
+ const ret = wasm.secretbytes_expose(this.__wbg_ptr);
52
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
53
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
54
+ return v1;
55
+ }
56
+ /**
57
+ * Length of the underlying secret in bytes.
58
+ * @returns {number}
59
+ */
60
+ get length() {
61
+ const ret = wasm.secretbytes_length(this.__wbg_ptr);
62
+ return ret >>> 0;
63
+ }
64
+ /**
65
+ * Wrap a byte buffer in a zeroize-on-drop handle.
66
+ *
67
+ * Useful from JS when a caller already has key material (e.g.,
68
+ * previously derived and cached across workers) and wants to hand it
69
+ * back into a WASM decrypt call without going through `expose`.
70
+ * @param {Uint8Array} bytes
71
+ */
72
+ constructor(bytes) {
73
+ const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
74
+ const len0 = WASM_VECTOR_LEN;
75
+ const ret = wasm.secretbytes_new(ptr0, len0);
76
+ this.__wbg_ptr = ret >>> 0;
77
+ SecretBytesFinalization.register(this, this.__wbg_ptr, this);
78
+ return this;
79
+ }
80
+ }
81
+ if (Symbol.dispose) SecretBytes.prototype[Symbol.dispose] = SecretBytes.prototype.free;
82
+
83
+ /**
84
+ * Opaque wrapper around a sensitive UTF-8 string (mnemonics, etc.).
85
+ *
86
+ * Internally stored as `Zeroizing<Vec<u8>>` — UTF-8 validated on
87
+ * construction, exposed on access. Using a `Vec<u8>` (rather than
88
+ * `String`) makes it harder to accidentally introduce mutation that
89
+ * would realloc and leak the old buffer.
90
+ *
91
+ * # Invariant
92
+ *
93
+ * The inner Vec is never mutated after construction. Any future change
94
+ * that mutates a `SecretString`'s inner bytes MUST ensure no
95
+ * reallocation occurs (reserve exact capacity up-front).
96
+ */
97
+ export class SecretString {
98
+ static __wrap(ptr) {
99
+ ptr = ptr >>> 0;
100
+ const obj = Object.create(SecretString.prototype);
101
+ obj.__wbg_ptr = ptr;
102
+ SecretStringFinalization.register(obj, obj.__wbg_ptr, obj);
103
+ return obj;
104
+ }
105
+ __destroy_into_raw() {
106
+ const ptr = this.__wbg_ptr;
107
+ this.__wbg_ptr = 0;
108
+ SecretStringFinalization.unregister(this);
109
+ return ptr;
110
+ }
111
+ free() {
112
+ const ptr = this.__destroy_into_raw();
113
+ wasm.__wbg_secretstring_free(ptr, 0);
114
+ }
115
+ /**
116
+ * Copy the string out to JS.
117
+ *
118
+ * The returned JS string lives on the V8 heap and cannot be zeroed.
119
+ * Minimize retention: decode, act, discard. For the most
120
+ * security-conscious callers, prefer [`Self::expose_bytes`] and
121
+ * decode via `TextDecoder`, then `fill(0)` the underlying byte
122
+ * buffer before any copy is made.
123
+ *
124
+ * Inherent limitation: wasm-bindgen's generated trampoline takes
125
+ * ownership of the returned `String` and drops it after marshaling
126
+ * to the JS heap. That final drop is outside our control and does
127
+ * not scrub. The Rust-side window is a single function call frame.
128
+ * @returns {string}
129
+ */
130
+ expose() {
131
+ let deferred1_0;
132
+ let deferred1_1;
133
+ try {
134
+ const ret = wasm.secretstring_expose(this.__wbg_ptr);
135
+ deferred1_0 = ret[0];
136
+ deferred1_1 = ret[1];
137
+ return getStringFromWasm0(ret[0], ret[1]);
138
+ } finally {
139
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
140
+ }
141
+ }
142
+ /**
143
+ * Copy the underlying UTF-8 bytes out as a `Uint8Array`.
144
+ *
145
+ * Prefer this over [`Self::expose`] when the caller wants the
146
+ * option to `fill(0)` the bytes in JS before they become an
147
+ * immutable JS string. Decode in JS with `new TextDecoder().decode(bytes)`.
148
+ * @returns {Uint8Array}
149
+ */
150
+ expose_bytes() {
151
+ const ret = wasm.secretstring_expose_bytes(this.__wbg_ptr);
152
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
153
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
154
+ return v1;
155
+ }
156
+ /**
157
+ * Length of the underlying secret in bytes (UTF-8 byte length, not
158
+ * Unicode scalar count).
159
+ * @returns {number}
160
+ */
161
+ get length() {
162
+ const ret = wasm.secretbytes_length(this.__wbg_ptr);
163
+ return ret >>> 0;
164
+ }
165
+ }
166
+ if (Symbol.dispose) SecretString.prototype[Symbol.dispose] = SecretString.prototype.free;
167
+
168
+ /**
169
+ * Derive a 32-byte key from a passphrase and salt using Argon2id.
170
+ *
171
+ * Exposed separately so the browser can perform the KDF step independently
172
+ * (e.g. to show a progress indicator while the KDF runs). Parameters are
173
+ * enforced against the OWASP 2023 minimum (see [`MIN_ARGON2_MEMORY_KIB`]).
174
+ * @param {string} passphrase
175
+ * @param {Uint8Array} salt
176
+ * @param {number} memory_kib
177
+ * @param {number} time_cost
178
+ * @param {number} parallelism
179
+ * @returns {SecretBytes}
180
+ */
181
+ export function argon2id_derive(passphrase, salt, memory_kib, time_cost, parallelism) {
182
+ const ptr0 = passStringToWasm0(passphrase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
183
+ const len0 = WASM_VECTOR_LEN;
184
+ const ptr1 = passArray8ToWasm0(salt, wasm.__wbindgen_malloc);
185
+ const len1 = WASM_VECTOR_LEN;
186
+ const ret = wasm.argon2id_derive(ptr0, len0, ptr1, len1, memory_kib, time_cost, parallelism);
187
+ if (ret[2]) {
188
+ throw takeFromExternrefTable0(ret[1]);
189
+ }
190
+ return SecretBytes.__wrap(ret[0]);
191
+ }
192
+
193
+ /**
194
+ * Decrypt a single HCFS file chunk using XChaCha20-Poly1305.
195
+ *
196
+ * The ciphertext includes the 16-byte Poly1305 auth tag appended at the end
197
+ * (same wire format as `hcfs-client` streaming encryption).
198
+ *
199
+ * - `key`: 32-byte encryption key (opaque handle)
200
+ * - `base_nonce`: 24-byte base nonce (from the file header)
201
+ * - `chunk_index`: 0-based chunk index (used to derive per-chunk nonce)
202
+ * - `ciphertext`: chunk ciphertext including the trailing 16-byte auth tag
203
+ *
204
+ * Returns the decrypted plaintext as a `Uint8Array`. On authentication
205
+ * failure the intermediate plaintext buffer is zeroized before the error
206
+ * returns.
207
+ * @param {SecretBytes} key
208
+ * @param {Uint8Array} base_nonce
209
+ * @param {number} chunk_index
210
+ * @param {Uint8Array} ciphertext
211
+ * @returns {Uint8Array}
212
+ */
213
+ export function decrypt_file_chunk(key, base_nonce, chunk_index, ciphertext) {
214
+ _assertClass(key, SecretBytes);
215
+ const ptr0 = passArray8ToWasm0(base_nonce, wasm.__wbindgen_malloc);
216
+ const len0 = WASM_VECTOR_LEN;
217
+ const ptr1 = passArray8ToWasm0(ciphertext, wasm.__wbindgen_malloc);
218
+ const len1 = WASM_VECTOR_LEN;
219
+ const ret = wasm.decrypt_file_chunk(key.__wbg_ptr, ptr0, len0, chunk_index, ptr1, len1);
220
+ if (ret[3]) {
221
+ throw takeFromExternrefTable0(ret[2]);
222
+ }
223
+ var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
224
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
225
+ return v3;
226
+ }
227
+
228
+ /**
229
+ * Derive a 32-byte per-folder encryption key from a master mnemonic and label.
230
+ *
231
+ * Chain: master → seed → SHA256(seed[..32] || label) → folder mnemonic → folder seed[..32].
232
+ * @param {string} master_mnemonic
233
+ * @param {string} label
234
+ * @returns {SecretBytes}
235
+ */
236
+ export function derive_file_key(master_mnemonic, label) {
237
+ const ptr0 = passStringToWasm0(master_mnemonic, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
238
+ const len0 = WASM_VECTOR_LEN;
239
+ const ptr1 = passStringToWasm0(label, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
240
+ const len1 = WASM_VECTOR_LEN;
241
+ const ret = wasm.derive_file_key(ptr0, len0, ptr1, len1);
242
+ if (ret[2]) {
243
+ throw takeFromExternrefTable0(ret[1]);
244
+ }
245
+ return SecretBytes.__wrap(ret[0]);
246
+ }
247
+
248
+ /**
249
+ * Derive a folder-specific mnemonic from a master mnemonic and folder label.
250
+ *
251
+ * Algorithm: `SHA256(master_seed[..32] || label)` → 32-byte entropy → 24-word mnemonic.
252
+ * @param {string} master
253
+ * @param {string} label
254
+ * @returns {SecretString}
255
+ */
256
+ export function derive_folder_mnemonic(master, label) {
257
+ const ptr0 = passStringToWasm0(master, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
258
+ const len0 = WASM_VECTOR_LEN;
259
+ const ptr1 = passStringToWasm0(label, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
260
+ const len1 = WASM_VECTOR_LEN;
261
+ const ret = wasm.derive_folder_mnemonic(ptr0, len0, ptr1, len1);
262
+ if (ret[2]) {
263
+ throw takeFromExternrefTable0(ret[1]);
264
+ }
265
+ return SecretString.__wrap(ret[0]);
266
+ }
267
+
268
+ /**
269
+ * Convert a BIP-39 mnemonic phrase to a 64-byte seed.
270
+ *
271
+ * Uses an empty passphrase for deterministic derivation (same as the
272
+ * native client). Returns a [`SecretBytes`] handle.
273
+ * @param {string} phrase
274
+ * @returns {SecretBytes}
275
+ */
276
+ export function mnemonic_to_seed(phrase) {
277
+ const ptr0 = passStringToWasm0(phrase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
278
+ const len0 = WASM_VECTOR_LEN;
279
+ const ret = wasm.mnemonic_to_seed(ptr0, len0);
280
+ if (ret[2]) {
281
+ throw takeFromExternrefTable0(ret[1]);
282
+ }
283
+ return SecretBytes.__wrap(ret[0]);
284
+ }
285
+
286
+ /**
287
+ * Decrypt a sealed mnemonic blob using a passphrase.
288
+ *
289
+ * `blob_json` is the JSON string of the `SealedBlob` (same shape as returned
290
+ * by `GET /v1/mnemonic-blob`). `passphrase` is the user's passphrase.
291
+ * `expected_ss58` is the SS58 address the caller believes owns this blob —
292
+ * it is used as the AEAD associated data. If the blob was sealed under a
293
+ * different SS58, the AEAD tag check will fail, preventing blob-swap attacks.
294
+ *
295
+ * KDF parameters carried inside the blob are validated against the same
296
+ * OWASP floor as [`argon2id_derive`]; a server that advertises weak params
297
+ * is rejected rather than trusted.
298
+ *
299
+ * Returns the decrypted mnemonic phrase as a [`SecretString`] handle.
300
+ * @param {string} blob_json
301
+ * @param {string} passphrase
302
+ * @param {string} expected_ss58
303
+ * @returns {SecretString}
304
+ */
305
+ export function open_mnemonic_blob(blob_json, passphrase, expected_ss58) {
306
+ const ptr0 = passStringToWasm0(blob_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
307
+ const len0 = WASM_VECTOR_LEN;
308
+ const ptr1 = passStringToWasm0(passphrase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
309
+ const len1 = WASM_VECTOR_LEN;
310
+ const ptr2 = passStringToWasm0(expected_ss58, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
311
+ const len2 = WASM_VECTOR_LEN;
312
+ const ret = wasm.open_mnemonic_blob(ptr0, len0, ptr1, len1, ptr2, len2);
313
+ if (ret[2]) {
314
+ throw takeFromExternrefTable0(ret[1]);
315
+ }
316
+ return SecretString.__wrap(ret[0]);
317
+ }
318
+
319
+ function __wbg_get_imports() {
320
+ const import0 = {
321
+ __proto__: null,
322
+ __wbg_Error_8c4e43fe74559d73: function(arg0, arg1) {
323
+ const ret = Error(getStringFromWasm0(arg0, arg1));
324
+ return ret;
325
+ },
326
+ __wbg___wbindgen_throw_be289d5034ed271b: function(arg0, arg1) {
327
+ throw new Error(getStringFromWasm0(arg0, arg1));
328
+ },
329
+ __wbindgen_init_externref_table: function() {
330
+ const table = wasm.__wbindgen_externrefs;
331
+ const offset = table.grow(4);
332
+ table.set(0, undefined);
333
+ table.set(offset + 0, undefined);
334
+ table.set(offset + 1, null);
335
+ table.set(offset + 2, true);
336
+ table.set(offset + 3, false);
337
+ },
338
+ };
339
+ return {
340
+ __proto__: null,
341
+ "./hcfs_client_wasm_bg.js": import0,
342
+ };
343
+ }
344
+
345
+ const SecretBytesFinalization = (typeof FinalizationRegistry === 'undefined')
346
+ ? { register: () => {}, unregister: () => {} }
347
+ : new FinalizationRegistry(ptr => wasm.__wbg_secretbytes_free(ptr >>> 0, 1));
348
+ const SecretStringFinalization = (typeof FinalizationRegistry === 'undefined')
349
+ ? { register: () => {}, unregister: () => {} }
350
+ : new FinalizationRegistry(ptr => wasm.__wbg_secretstring_free(ptr >>> 0, 1));
351
+
352
+ function _assertClass(instance, klass) {
353
+ if (!(instance instanceof klass)) {
354
+ throw new Error(`expected instance of ${klass.name}`);
355
+ }
356
+ }
357
+
358
+ function getArrayU8FromWasm0(ptr, len) {
359
+ ptr = ptr >>> 0;
360
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
361
+ }
362
+
363
+ function getStringFromWasm0(ptr, len) {
364
+ ptr = ptr >>> 0;
365
+ return decodeText(ptr, len);
366
+ }
367
+
368
+ let cachedUint8ArrayMemory0 = null;
369
+ function getUint8ArrayMemory0() {
370
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
371
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
372
+ }
373
+ return cachedUint8ArrayMemory0;
374
+ }
375
+
376
+ function passArray8ToWasm0(arg, malloc) {
377
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
378
+ getUint8ArrayMemory0().set(arg, ptr / 1);
379
+ WASM_VECTOR_LEN = arg.length;
380
+ return ptr;
381
+ }
382
+
383
+ function passStringToWasm0(arg, malloc, realloc) {
384
+ if (realloc === undefined) {
385
+ const buf = cachedTextEncoder.encode(arg);
386
+ const ptr = malloc(buf.length, 1) >>> 0;
387
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
388
+ WASM_VECTOR_LEN = buf.length;
389
+ return ptr;
390
+ }
391
+
392
+ let len = arg.length;
393
+ let ptr = malloc(len, 1) >>> 0;
394
+
395
+ const mem = getUint8ArrayMemory0();
396
+
397
+ let offset = 0;
398
+
399
+ for (; offset < len; offset++) {
400
+ const code = arg.charCodeAt(offset);
401
+ if (code > 0x7F) break;
402
+ mem[ptr + offset] = code;
403
+ }
404
+ if (offset !== len) {
405
+ if (offset !== 0) {
406
+ arg = arg.slice(offset);
407
+ }
408
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
409
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
410
+ const ret = cachedTextEncoder.encodeInto(arg, view);
411
+
412
+ offset += ret.written;
413
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
414
+ }
415
+
416
+ WASM_VECTOR_LEN = offset;
417
+ return ptr;
418
+ }
419
+
420
+ function takeFromExternrefTable0(idx) {
421
+ const value = wasm.__wbindgen_externrefs.get(idx);
422
+ wasm.__externref_table_dealloc(idx);
423
+ return value;
424
+ }
425
+
426
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
427
+ cachedTextDecoder.decode();
428
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
429
+ let numBytesDecoded = 0;
430
+ function decodeText(ptr, len) {
431
+ numBytesDecoded += len;
432
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
433
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
434
+ cachedTextDecoder.decode();
435
+ numBytesDecoded = len;
436
+ }
437
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
438
+ }
439
+
440
+ const cachedTextEncoder = new TextEncoder();
441
+
442
+ if (!('encodeInto' in cachedTextEncoder)) {
443
+ cachedTextEncoder.encodeInto = function (arg, view) {
444
+ const buf = cachedTextEncoder.encode(arg);
445
+ view.set(buf);
446
+ return {
447
+ read: arg.length,
448
+ written: buf.length
449
+ };
450
+ };
451
+ }
452
+
453
+ let WASM_VECTOR_LEN = 0;
454
+
455
+ let wasmModule, wasm;
456
+ function __wbg_finalize_init(instance, module) {
457
+ wasm = instance.exports;
458
+ wasmModule = module;
459
+ cachedUint8ArrayMemory0 = null;
460
+ wasm.__wbindgen_start();
461
+ return wasm;
462
+ }
463
+
464
+ async function __wbg_load(module, imports) {
465
+ if (typeof Response === 'function' && module instanceof Response) {
466
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
467
+ try {
468
+ return await WebAssembly.instantiateStreaming(module, imports);
469
+ } catch (e) {
470
+ const validResponse = module.ok && expectedResponseType(module.type);
471
+
472
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
473
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
474
+
475
+ } else { throw e; }
476
+ }
477
+ }
478
+
479
+ const bytes = await module.arrayBuffer();
480
+ return await WebAssembly.instantiate(bytes, imports);
481
+ } else {
482
+ const instance = await WebAssembly.instantiate(module, imports);
483
+
484
+ if (instance instanceof WebAssembly.Instance) {
485
+ return { instance, module };
486
+ } else {
487
+ return instance;
488
+ }
489
+ }
490
+
491
+ function expectedResponseType(type) {
492
+ switch (type) {
493
+ case 'basic': case 'cors': case 'default': return true;
494
+ }
495
+ return false;
496
+ }
497
+ }
498
+
499
+ function initSync(module) {
500
+ if (wasm !== undefined) return wasm;
501
+
502
+
503
+ if (module !== undefined) {
504
+ if (Object.getPrototypeOf(module) === Object.prototype) {
505
+ ({module} = module)
506
+ } else {
507
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
508
+ }
509
+ }
510
+
511
+ const imports = __wbg_get_imports();
512
+ if (!(module instanceof WebAssembly.Module)) {
513
+ module = new WebAssembly.Module(module);
514
+ }
515
+ const instance = new WebAssembly.Instance(module, imports);
516
+ return __wbg_finalize_init(instance, module);
517
+ }
518
+
519
+ async function __wbg_init(module_or_path) {
520
+ if (wasm !== undefined) return wasm;
521
+
522
+
523
+ if (module_or_path !== undefined) {
524
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
525
+ ({module_or_path} = module_or_path)
526
+ } else {
527
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
528
+ }
529
+ }
530
+
531
+ if (module_or_path === undefined) {
532
+ module_or_path = new URL('hcfs_client_wasm_bg.wasm', import.meta.url);
533
+ }
534
+ const imports = __wbg_get_imports();
535
+
536
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
537
+ module_or_path = fetch(module_or_path);
538
+ }
539
+
540
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
541
+
542
+ return __wbg_finalize_init(instance, module);
543
+ }
544
+
545
+ export { initSync, __wbg_init as default };
Binary file
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@hippius/hcfs-client-wasm",
3
+ "type": "module",
4
+ "description": "HCFS cryptographic primitives compiled to WebAssembly for browser use",
5
+ "version": "0.1.2",
6
+ "files": [
7
+ "hcfs_client_wasm_bg.wasm",
8
+ "hcfs_client_wasm.js",
9
+ "hcfs_client_wasm.d.ts"
10
+ ],
11
+ "main": "hcfs_client_wasm.js",
12
+ "types": "hcfs_client_wasm.d.ts",
13
+ "sideEffects": [
14
+ "./snippets/*"
15
+ ]
16
+ }