@hugomrdias/commp-wasm 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @hugomrdias/commp-wasm
2
+
3
+ Fast CommP (Filecoin Piece Commitment) in Rust/WASM with 4-lane SIMD SHA-256. The WASM is inlined as base64, so there is no async init and no bundler configuration.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @hugomrdias/commp-wasm
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```javascript
14
+ import { create, digest, root } from '@hugomrdias/commp-wasm'
15
+
16
+ // One-shot: just the 32-byte root
17
+ const rootHash = root(data)
18
+
19
+ // One-shot: full multihash digest with metadata
20
+ const result = digest(data)
21
+
22
+ // Streaming: for large files
23
+ const hasher = create()
24
+ for (const chunk of chunks) {
25
+ hasher.write(chunk)
26
+ }
27
+ const streamResult = hasher.digest()
28
+ hasher.free() // Free WASM memory when done
29
+ ```
30
+
31
+ See the [repository README](https://github.com/hugomrdias/commp#readme) for the full API and benchmarks.
32
+
33
+ ## License
34
+
35
+ MIT
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@hugomrdias/commp-wasm",
3
+ "version": "0.0.0",
4
+ "description": "Fast CommP (Filecoin Piece Commitment) WASM implementation with inline base64",
5
+ "keywords": [
6
+ "filecoin",
7
+ "commp",
8
+ "piece-commitment",
9
+ "wasm",
10
+ "merkle-tree",
11
+ "fr32"
12
+ ],
13
+ "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/hugomrdias/commp.git",
17
+ "directory": "packages/commp-wasm"
18
+ },
19
+ "type": "module",
20
+ "main": "./src/index.js",
21
+ "types": "./src/types.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./src/types.ts",
25
+ "import": "./src/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "src",
30
+ "CHANGELOG.md"
31
+ ],
32
+ "devDependencies": {
33
+ "@hugomrdias/commp-js": "0.0.0",
34
+ "@web3-storage/data-segment": "^5.3.0",
35
+ "mocha": "^12.0.2"
36
+ },
37
+ "scripts": {
38
+ "build:rust": "cd ../../rs/commp && RUSTFLAGS=\"-C target-feature=+simd128 --remap-path-prefix=${CARGO_HOME:-$HOME/.cargo}=/cargo\" wasm-pack build --target bundler --out-dir ../../packages/commp-wasm/pkg-bundler --release",
39
+ "build:inline": "node scripts/build-inline-wasm.js",
40
+ "build:wasm": "pnpm build:rust && pnpm build:inline",
41
+ "clean": "rm -rf pkg-bundler",
42
+ "test": "mocha \"tests/**/*.test.js\"",
43
+ "lint": "biome check ."
44
+ }
45
+ }
package/src/index.js ADDED
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Fast CommP (Filecoin Piece Commitment) WASM implementation
3
+ *
4
+ * This module provides a high-performance CommP calculation using
5
+ * Rust/WASM with inline base64 encoding - no async init required.
6
+ *
7
+ * @module @hugomrdias/commp-wasm
8
+ */
9
+
10
+ import { CommPHasher as WasmHasher, root as wasmRoot } from './inline/commp.js'
11
+ import { decode as varintDecode } from './varint.js'
12
+
13
+ /** @import { PieceDigest, StreamingHasher } from './types.js' */
14
+
15
+ /**
16
+ * Largest slice passed to WASM per call. wasm-bindgen copies each input into
17
+ * WASM memory, which never shrinks, so large inputs are fed in chunks.
18
+ */
19
+ const CHUNK_SIZE = 1 << 20
20
+
21
+ /** Multihash code for fr32-sha2-256-trunc254-padded-binary-tree */
22
+ export const code = 0x1011
23
+
24
+ /** Multihash name */
25
+ export const name = /** @type {const} */ (
26
+ 'fr32-sha2-256-trunc254-padded-binary-tree'
27
+ )
28
+
29
+ /**
30
+ * Streaming CommP hasher
31
+ *
32
+ * @example
33
+ * ```ts twoslash
34
+ * import { create } from '@hugomrdias/commp-wasm'
35
+ *
36
+ * const hasher = create()
37
+ * hasher.write(new Uint8Array(1024).fill(0x42))
38
+ * hasher.write(new Uint8Array(1024).fill(0x43))
39
+ * const digest = hasher.digest()
40
+ * console.log(digest.root) // 32-byte root hash
41
+ * ```
42
+ *
43
+ * @implements {StreamingHasher}
44
+ */
45
+ class Hasher {
46
+ constructor() {
47
+ /**
48
+ * @private
49
+ * @type {WasmHasher}
50
+ */
51
+ this.inner = new WasmHasher()
52
+ }
53
+
54
+ /**
55
+ * Get the total number of bytes written
56
+ *
57
+ * @returns {bigint}
58
+ */
59
+ count() {
60
+ return BigInt(this.inner.count())
61
+ }
62
+
63
+ /**
64
+ * Write bytes into the hasher
65
+ *
66
+ * @param {Uint8Array} bytes - Bytes to write
67
+ * @returns {this}
68
+ * @throws {RangeError} If the total would exceed `MAX_PAYLOAD_SIZE`; the
69
+ * hasher is left unchanged
70
+ */
71
+ write(bytes) {
72
+ // Rust checks each chunk; check the whole write first so a rejected write
73
+ // never leaves earlier chunks applied
74
+ if (
75
+ bytes.length > CHUNK_SIZE &&
76
+ this.count() + BigInt(bytes.length) > MAX_PAYLOAD_SIZE
77
+ ) {
78
+ throw new RangeError(
79
+ `Writing ${bytes.length} bytes exceeds max payload size of ${MAX_PAYLOAD_SIZE}`
80
+ )
81
+ }
82
+ for (let offset = 0; offset < bytes.length; offset += CHUNK_SIZE) {
83
+ this.inner.write(bytes.subarray(offset, offset + CHUNK_SIZE))
84
+ }
85
+ return this
86
+ }
87
+
88
+ /**
89
+ * Compute the digest
90
+ *
91
+ * @returns {PieceDigest}
92
+ */
93
+ digest() {
94
+ // Format: code (varint) | size (varint) | padding (varint) | height | root
95
+ const bytes = this.inner.digest()
96
+ const [, codeLength] = varintDecode(bytes, 0)
97
+ const [, sizeLength] = varintDecode(bytes, codeLength)
98
+ const digestStart = codeLength + sizeLength
99
+ const [padding] = varintDecode(bytes, digestStart)
100
+
101
+ return {
102
+ code,
103
+ name,
104
+ digest: bytes.subarray(digestStart),
105
+ bytes,
106
+ height: bytes[bytes.length - ROOT_SIZE - HEIGHT_SIZE],
107
+ root: bytes.slice(-ROOT_SIZE),
108
+ padding,
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Reset the hasher to initial state
114
+ *
115
+ * @returns {this}
116
+ */
117
+ reset() {
118
+ this.inner.reset()
119
+ return this
120
+ }
121
+
122
+ /**
123
+ * Dispose of resources
124
+ */
125
+ dispose() {
126
+ this.inner.free()
127
+ }
128
+
129
+ /**
130
+ * Free WASM resources (alias for dispose)
131
+ */
132
+ free() {
133
+ this.inner.free()
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Creates a new streaming CommP hasher
139
+ *
140
+ * @example
141
+ * ```ts twoslash
142
+ * import { create, digest } from '@hugomrdias/commp-wasm'
143
+ *
144
+ * // Streaming API
145
+ * const hasher = create()
146
+ * hasher.write(chunk1)
147
+ * hasher.write(chunk2)
148
+ * const result = hasher.digest()
149
+ *
150
+ * // One-shot API
151
+ * const result2 = digest(fullData)
152
+ * ```
153
+ *
154
+ * @returns {Hasher}
155
+ */
156
+ export function create() {
157
+ return new Hasher()
158
+ }
159
+
160
+ /**
161
+ * Computes CommP digest of a complete payload (one-shot)
162
+ *
163
+ * @example
164
+ * ```ts twoslash
165
+ * import { digest } from '@hugomrdias/commp-wasm'
166
+ *
167
+ * const data = new Uint8Array(1024 * 1024).fill(0x42)
168
+ * const result = digest(data)
169
+ * console.log(result.root) // 32-byte piece commitment
170
+ * ```
171
+ *
172
+ * @param {Uint8Array} payload - Data to compute CommP for
173
+ * @returns {PieceDigest}
174
+ */
175
+ export function digest(payload) {
176
+ const hasher = create()
177
+ try {
178
+ return hasher.write(payload).digest()
179
+ } finally {
180
+ hasher.free()
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Computes just the 32-byte root hash (faster, less allocations)
186
+ *
187
+ * @example
188
+ * ```ts twoslash
189
+ * import { root } from '@hugomrdias/commp-wasm'
190
+ *
191
+ * const data = new Uint8Array(1024 * 1024).fill(0x42)
192
+ * const rootHash = root(data)
193
+ * console.log(rootHash) // 32-byte Uint8Array
194
+ * ```
195
+ *
196
+ * @param {Uint8Array} payload - Data to compute CommP for
197
+ * @returns {Uint8Array}
198
+ */
199
+ export function root(payload) {
200
+ if (payload.length <= CHUNK_SIZE) {
201
+ return wasmRoot(payload)
202
+ }
203
+ const hasher = create()
204
+ try {
205
+ hasher.write(payload)
206
+ return hasher.inner.root()
207
+ } finally {
208
+ hasher.free()
209
+ }
210
+ }
211
+
212
+ // Re-export constants
213
+ export const NODE_SIZE = 32
214
+ export const IN_BYTES_PER_QUAD = 127
215
+ export const MIN_PAYLOAD_SIZE = 65
216
+
217
+ /**
218
+ * Largest payload accepted, in bytes: 127 * 2^47 (~15.9 PiB)
219
+ *
220
+ * data-segment allows up to tree height 255, far beyond 64 bits. This is the
221
+ * largest payload for which every derived size (padding, piece size) stays
222
+ * below 2^53, so the digest fields are exact as JS numbers.
223
+ */
224
+ export const MAX_PAYLOAD_SIZE = 127n << 47n
225
+ export const HEIGHT_SIZE = 1
226
+ export const ROOT_SIZE = 32
@@ -0,0 +1,13 @@
1
+ // Auto-generated - do not edit
2
+ // CommP WASM with inline base64 encoding
3
+
4
+ import { wasm } from "./commp_bg.wasm.js";
5
+ export * from "./commp_bg.js";
6
+ import { __wbg_set_wasm } from "./commp_bg.js";
7
+
8
+ __wbg_set_wasm(wasm);
9
+
10
+ // Run wasm start function if present
11
+ if (wasm.__wbindgen_start) {
12
+ wasm.__wbindgen_start();
13
+ }
@@ -0,0 +1,269 @@
1
+ let wasm;
2
+ export function __wbg_set_wasm(val) {
3
+ wasm = val;
4
+ }
5
+
6
+ function addHeapObject(obj) {
7
+ if (heap_next === heap.length) heap.push(heap.length + 1);
8
+ const idx = heap_next;
9
+ heap_next = heap[idx];
10
+
11
+ heap[idx] = obj;
12
+ return idx;
13
+ }
14
+
15
+ function dropObject(idx) {
16
+ if (idx < 132) return;
17
+ heap[idx] = heap_next;
18
+ heap_next = idx;
19
+ }
20
+
21
+ function getArrayU8FromWasm0(ptr, len) {
22
+ ptr = ptr >>> 0;
23
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
24
+ }
25
+
26
+ let cachedDataViewMemory0 = null;
27
+ function getDataViewMemory0() {
28
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
29
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
30
+ }
31
+ return cachedDataViewMemory0;
32
+ }
33
+
34
+ function getStringFromWasm0(ptr, len) {
35
+ ptr = ptr >>> 0;
36
+ return decodeText(ptr, len);
37
+ }
38
+
39
+ let cachedUint8ArrayMemory0 = null;
40
+ function getUint8ArrayMemory0() {
41
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
42
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
43
+ }
44
+ return cachedUint8ArrayMemory0;
45
+ }
46
+
47
+ function getObject(idx) { return heap[idx]; }
48
+
49
+ let heap = new Array(128).fill(undefined);
50
+ heap.push(undefined, null, true, false);
51
+
52
+ let heap_next = heap.length;
53
+
54
+ function passArray8ToWasm0(arg, malloc) {
55
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
56
+ getUint8ArrayMemory0().set(arg, ptr / 1);
57
+ WASM_VECTOR_LEN = arg.length;
58
+ return ptr;
59
+ }
60
+
61
+ function takeObject(idx) {
62
+ const ret = getObject(idx);
63
+ dropObject(idx);
64
+ return ret;
65
+ }
66
+
67
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
68
+ cachedTextDecoder.decode();
69
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
70
+ let numBytesDecoded = 0;
71
+ function decodeText(ptr, len) {
72
+ numBytesDecoded += len;
73
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
74
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
75
+ cachedTextDecoder.decode();
76
+ numBytesDecoded = len;
77
+ }
78
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
79
+ }
80
+
81
+ let WASM_VECTOR_LEN = 0;
82
+
83
+ const CommPHasherFinalization = (typeof FinalizationRegistry === 'undefined')
84
+ ? { register: () => {}, unregister: () => {} }
85
+ : new FinalizationRegistry(ptr => wasm.__wbg_commphasher_free(ptr >>> 0, 1));
86
+
87
+ /**
88
+ * Streaming CommP hasher with O(log n) memory
89
+ */
90
+ export class CommPHasher {
91
+ __destroy_into_raw() {
92
+ const ptr = this.__wbg_ptr;
93
+ this.__wbg_ptr = 0;
94
+ CommPHasherFinalization.unregister(this);
95
+ return ptr;
96
+ }
97
+ free() {
98
+ const ptr = this.__destroy_into_raw();
99
+ wasm.__wbg_commphasher_free(ptr, 0);
100
+ }
101
+ /**
102
+ * Create a new hasher
103
+ */
104
+ constructor() {
105
+ const ret = wasm.commphasher_new();
106
+ this.__wbg_ptr = ret >>> 0;
107
+ CommPHasherFinalization.register(this, this.__wbg_ptr, this);
108
+ return this;
109
+ }
110
+ /**
111
+ * Get just the 32-byte CommP root hash
112
+ *
113
+ * Returns the raw Merkle root without multihash encoding.
114
+ * Use `digest()` if you need the full multihash with metadata.
115
+ * @returns {Uint8Array}
116
+ */
117
+ root() {
118
+ try {
119
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
120
+ wasm.commphasher_root(retptr, this.__wbg_ptr);
121
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
122
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
123
+ var v1 = getArrayU8FromWasm0(r0, r1).slice();
124
+ wasm.__wbindgen_export(r0, r1 * 1, 1);
125
+ return v1;
126
+ } finally {
127
+ wasm.__wbindgen_add_to_stack_pointer(16);
128
+ }
129
+ }
130
+ /**
131
+ * Get bytes written count
132
+ * @returns {bigint}
133
+ */
134
+ count() {
135
+ const ret = wasm.commphasher_count(this.__wbg_ptr);
136
+ return BigInt.asUintN(64, ret);
137
+ }
138
+ /**
139
+ * Reset the hasher for reuse
140
+ */
141
+ reset() {
142
+ wasm.commphasher_reset(this.__wbg_ptr);
143
+ }
144
+ /**
145
+ * Write bytes into the hasher
146
+ *
147
+ * Throws a `RangeError` (without changing the hasher) if the total would
148
+ * exceed `MAX_PAYLOAD_SIZE`.
149
+ * @param {Uint8Array} bytes
150
+ */
151
+ write(bytes) {
152
+ try {
153
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
154
+ const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_export2);
155
+ const len0 = WASM_VECTOR_LEN;
156
+ wasm.commphasher_write(retptr, this.__wbg_ptr, ptr0, len0);
157
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
158
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
159
+ if (r1) {
160
+ throw takeObject(r0);
161
+ }
162
+ } finally {
163
+ wasm.__wbindgen_add_to_stack_pointer(16);
164
+ }
165
+ }
166
+ /**
167
+ * Get the full multihash-encoded digest
168
+ *
169
+ * Returns: [code (varint 0x1011), size (varint), padding (varint), height (u8), root (32 bytes)]
170
+ *
171
+ * - `code`: 0x1011 = "fr32-sha256-trunc254-padded-binary-tree" multihash identifier
172
+ * - `size`: total digest size (padding_len + 1 + 32)
173
+ * - `padding`: bytes of zero-padding added to reach next power-of-two piece size
174
+ * - `height`: tree height (log2 of piece size / 32)
175
+ * - `root`: 32-byte Merkle root
176
+ * @returns {Uint8Array}
177
+ */
178
+ digest() {
179
+ try {
180
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
181
+ wasm.commphasher_digest(retptr, this.__wbg_ptr);
182
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
183
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
184
+ var v1 = getArrayU8FromWasm0(r0, r1).slice();
185
+ wasm.__wbindgen_export(r0, r1 * 1, 1);
186
+ return v1;
187
+ } finally {
188
+ wasm.__wbindgen_add_to_stack_pointer(16);
189
+ }
190
+ }
191
+ /**
192
+ * Get the tree height
193
+ * @returns {number}
194
+ */
195
+ height() {
196
+ const ret = wasm.commphasher_height(this.__wbg_ptr);
197
+ return ret;
198
+ }
199
+ }
200
+ if (Symbol.dispose) CommPHasher.prototype[Symbol.dispose] = CommPHasher.prototype.free;
201
+
202
+ /**
203
+ * One-shot digest: returns full multihash-encoded CommP
204
+ *
205
+ * Format: [code (varint 0x1011), size (varint), padding (varint), height (u8), root (32 bytes)]
206
+ *
207
+ * Use this when you need the complete Filecoin piece commitment with metadata.
208
+ * The multihash code 0x1011 identifies this as "fr32-sha256-trunc254-padded-binary-tree".
209
+ * @param {Uint8Array} data
210
+ * @returns {Uint8Array}
211
+ */
212
+ export function digest(data) {
213
+ try {
214
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
215
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export2);
216
+ const len0 = WASM_VECTOR_LEN;
217
+ wasm.digest(retptr, ptr0, len0);
218
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
219
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
220
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
221
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
222
+ if (r3) {
223
+ throw takeObject(r2);
224
+ }
225
+ var v2 = getArrayU8FromWasm0(r0, r1).slice();
226
+ wasm.__wbindgen_export(r0, r1 * 1, 1);
227
+ return v2;
228
+ } finally {
229
+ wasm.__wbindgen_add_to_stack_pointer(16);
230
+ }
231
+ }
232
+
233
+ /**
234
+ * One-shot root: returns just the 32-byte CommP root hash
235
+ *
236
+ * Use this when you only need the raw hash without multihash encoding.
237
+ * This is the Merkle root of the FR32-padded, SHA256-hashed binary tree.
238
+ * @param {Uint8Array} data
239
+ * @returns {Uint8Array}
240
+ */
241
+ export function root(data) {
242
+ try {
243
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
244
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export2);
245
+ const len0 = WASM_VECTOR_LEN;
246
+ wasm.root(retptr, ptr0, len0);
247
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
248
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
249
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
250
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
251
+ if (r3) {
252
+ throw takeObject(r2);
253
+ }
254
+ var v2 = getArrayU8FromWasm0(r0, r1).slice();
255
+ wasm.__wbindgen_export(r0, r1 * 1, 1);
256
+ return v2;
257
+ } finally {
258
+ wasm.__wbindgen_add_to_stack_pointer(16);
259
+ }
260
+ }
261
+
262
+ export function __wbg___wbindgen_throw_dd24417ed36fc46e(arg0, arg1) {
263
+ throw new Error(getStringFromWasm0(arg0, arg1));
264
+ };
265
+
266
+ export function __wbg_new_9909933006805bd0(arg0, arg1) {
267
+ const ret = new RangeError(getStringFromWasm0(arg0, arg1));
268
+ return addHeapObject(ret);
269
+ };
@@ -0,0 +1,29 @@
1
+ // Auto-generated - do not edit
2
+ // WASM binary embedded as base64 for synchronous loading
3
+
4
+ import * as commp_bg from './commp_bg.js';
5
+
6
+ const wasmBase64 = "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";
7
+
8
+ // Decode base64 to Uint8Array, fastest available method first
9
+ function base64ToBytes(base64) {
10
+ if (typeof Uint8Array.fromBase64 === 'function') {
11
+ return Uint8Array.fromBase64(base64);
12
+ }
13
+ if (typeof globalThis.Buffer === 'function') {
14
+ return globalThis.Buffer.from(base64, 'base64');
15
+ }
16
+ const binary = atob(base64);
17
+ const bytes = new Uint8Array(binary.length);
18
+ for (let i = 0; i < binary.length; i++) {
19
+ bytes[i] = binary.charCodeAt(i);
20
+ }
21
+ return bytes;
22
+ }
23
+
24
+ const wasmBinary = base64ToBytes(wasmBase64);
25
+ const wasmModule = new WebAssembly.Module(wasmBinary);
26
+ const importObject = { './commp_bg.js': commp_bg };
27
+ const wasm = new WebAssembly.Instance(wasmModule, importObject).exports;
28
+
29
+ export { wasm };
package/src/types.ts ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Type definitions for CommP WASM implementation
3
+ */
4
+
5
+ /** Streaming hasher interface */
6
+ export interface StreamingHasher {
7
+ /** Write bytes into the hasher */
8
+ write(bytes: Uint8Array): this
9
+ /** Get the total bytes written */
10
+ count(): bigint
11
+ /** Compute the digest without consuming the hasher */
12
+ digest(): PieceDigest
13
+ /** Reset the hasher to initial state */
14
+ reset(): this
15
+ /** Free resources */
16
+ dispose(): void
17
+ /** Free WASM resources (alias for dispose) */
18
+ free(): void
19
+ }
20
+
21
+ /** Piece digest result */
22
+ export interface PieceDigest {
23
+ /** Multihash code */
24
+ code: 0x1011
25
+ /** Multihash name */
26
+ name: 'fr32-sha2-256-trunc254-padded-binary-tree'
27
+ /** Raw digest bytes (padding + height + root) */
28
+ digest: Uint8Array
29
+ /** Full multihash bytes (code + size + digest) */
30
+ bytes: Uint8Array
31
+ /** Tree height */
32
+ height: number
33
+ /** 32-byte root hash */
34
+ root: Uint8Array
35
+ /** Zero padding applied */
36
+ padding: number
37
+ }
package/src/varint.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Unsigned varint (LEB128) decoding
3
+ *
4
+ * Uses arithmetic instead of 32-bit bitwise operators so values up to
5
+ * `Number.MAX_SAFE_INTEGER` decode correctly.
6
+ *
7
+ * @module
8
+ */
9
+
10
+ /**
11
+ * Decodes a varint from the buffer at the given offset
12
+ *
13
+ * @param {Uint8Array} buf - Buffer to read from
14
+ * @param {number} offset - Offset to start reading
15
+ * @returns {[value: number, length: number]} - Decoded value and bytes read
16
+ */
17
+ export function decode(buf, offset) {
18
+ let value = 0
19
+ let scale = 1
20
+ let i = offset
21
+ while (buf[i] & 0x80) {
22
+ value += (buf[i] & 0x7f) * scale
23
+ scale *= 0x80
24
+ i++
25
+ }
26
+ value += buf[i] * scale
27
+ return [value, i - offset + 1]
28
+ }