@hugomrdias/commp-wasm 0.1.1 → 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.2](https://github.com/hugomrdias/commp/compare/commp-wasm-v0.1.1...commp-wasm-v0.1.2) (2026-10-01)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * publish type declarations generated from JSDoc ([#32](https://github.com/hugomrdias/commp/issues/32)) ([4b7654e](https://github.com/hugomrdias/commp/commit/4b7654e9f793477f2b237f826bfdbdb937d56d98))
9
+
3
10
  ## [0.1.1](https://github.com/hugomrdias/commp/compare/commp-wasm-v0.1.0...commp-wasm-v0.1.1) (2026-09-30)
4
11
 
5
12
 
@@ -0,0 +1,135 @@
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
+ export type PieceDigest = import('./types.js').PieceDigest;
10
+ export type StreamingHasher = import('./types.js').StreamingHasher;
11
+ /** Multihash code for fr32-sha2-256-trunc254-padded-binary-tree */
12
+ export declare const code = 4113;
13
+ /** Multihash name */
14
+ export declare const name: 'fr32-sha2-256-trunc254-padded-binary-tree';
15
+ /**
16
+ * Streaming CommP hasher
17
+ *
18
+ * @example
19
+ * ```ts twoslash
20
+ * import { create } from '@hugomrdias/commp-wasm'
21
+ *
22
+ * const hasher = create()
23
+ * hasher.write(new Uint8Array(1024).fill(0x42))
24
+ * hasher.write(new Uint8Array(1024).fill(0x43))
25
+ * const digest = hasher.digest()
26
+ * console.log(digest.root) // 32-byte root hash
27
+ * ```
28
+ *
29
+ * @implements {StreamingHasher}
30
+ */
31
+ declare class Hasher implements StreamingHasher {
32
+ #private;
33
+ /**
34
+ * Get the total number of bytes written
35
+ *
36
+ * @returns {bigint}
37
+ */
38
+ count(): bigint;
39
+ /**
40
+ * Write bytes into the hasher
41
+ *
42
+ * @param {Uint8Array} bytes - Bytes to write
43
+ * @returns {this}
44
+ * @throws {RangeError} If the total would exceed `MAX_PAYLOAD_SIZE`; the
45
+ * hasher is left unchanged
46
+ */
47
+ write(bytes: Uint8Array): this;
48
+ /**
49
+ * Compute the digest
50
+ *
51
+ * @returns {PieceDigest}
52
+ */
53
+ digest(): PieceDigest;
54
+ /**
55
+ * Reset the hasher to initial state
56
+ *
57
+ * @returns {this}
58
+ */
59
+ reset(): this;
60
+ /**
61
+ * Dispose of resources
62
+ */
63
+ dispose(): void;
64
+ /**
65
+ * Free WASM resources (alias for dispose)
66
+ */
67
+ free(): void;
68
+ }
69
+ /**
70
+ * Creates a new streaming CommP hasher
71
+ *
72
+ * @example
73
+ * ```ts twoslash
74
+ * import { create, digest } from '@hugomrdias/commp-wasm'
75
+ *
76
+ * // Streaming API
77
+ * const hasher = create()
78
+ * hasher.write(chunk1)
79
+ * hasher.write(chunk2)
80
+ * const result = hasher.digest()
81
+ *
82
+ * // One-shot API
83
+ * const result2 = digest(fullData)
84
+ * ```
85
+ *
86
+ * @returns {Hasher}
87
+ */
88
+ export declare function create(): Hasher;
89
+ /**
90
+ * Computes CommP digest of a complete payload (one-shot)
91
+ *
92
+ * @example
93
+ * ```ts twoslash
94
+ * import { digest } from '@hugomrdias/commp-wasm'
95
+ *
96
+ * const data = new Uint8Array(1024 * 1024).fill(0x42)
97
+ * const result = digest(data)
98
+ * console.log(result.root) // 32-byte piece commitment
99
+ * ```
100
+ *
101
+ * @param {Uint8Array} payload - Data to compute CommP for
102
+ * @returns {PieceDigest}
103
+ */
104
+ export declare function digest(payload: Uint8Array): PieceDigest;
105
+ /**
106
+ * Computes just the 32-byte root hash (faster, less allocations)
107
+ *
108
+ * @example
109
+ * ```ts twoslash
110
+ * import { root } from '@hugomrdias/commp-wasm'
111
+ *
112
+ * const data = new Uint8Array(1024 * 1024).fill(0x42)
113
+ * const rootHash = root(data)
114
+ * console.log(rootHash) // 32-byte Uint8Array
115
+ * ```
116
+ *
117
+ * @param {Uint8Array} payload - Data to compute CommP for
118
+ * @returns {Uint8Array}
119
+ */
120
+ export declare function root(payload: Uint8Array): Uint8Array;
121
+ export declare const NODE_SIZE = 32;
122
+ export declare const IN_BYTES_PER_QUAD = 127;
123
+ export declare const MIN_PAYLOAD_SIZE = 65;
124
+ /**
125
+ * Largest payload accepted, in bytes: 127 * 2^47 (~15.9 PiB)
126
+ *
127
+ * data-segment allows up to tree height 255, far beyond 64 bits. This is the
128
+ * largest payload for which every derived size (padding, piece size) stays
129
+ * below 2^53, so the digest fields are exact as JS numbers.
130
+ */
131
+ export declare const MAX_PAYLOAD_SIZE: bigint;
132
+ export declare const HEIGHT_SIZE = 1;
133
+ export declare const ROOT_SIZE = 32;
134
+ export {};
135
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMA,YAA4C,WAAW,GAA7C,OAAO,YAAY,EAAE,WAAW,CAAa;AACvD,YAAgD,eAAe,GAArD,OAAO,YAAY,EAAE,eAAe,CAAiB;AASlE,mEAAmE;AACnE,eAAO,MAAM,IAAI,OAAS,CAAA;AAE1B,qBAAqB;AACrB,eAAO,MAAM,IAAI,EACf,2CACD,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,cAAM,MAAM,AAFI,YAAA,eAAe;;IAK7B;;;;OAIG;IACH,KAAK,IAFQ,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,EALA,UAKA,GAJE,IAAI,CAmBhB;IAED;;;;OAIG;IACH,MAAM,IAFO,WAAW,CAmBvB;IAED;;;;OAIG;IACH,KAAK,IAFQ,IAAI,CAKhB;IAED;;OAEG;IACH,OAAO,SAEN;IAED;;OAEG;IACH,IAAI,SAEH;CACF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,MAAM,IAFT,MAAM,CAIlB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAHnB,UAGmB,GAFjB,WAAW,CASvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAHjB,UAGiB,GAFf,UAAU,CAetB;AAGD,eAAO,MAAM,SAAS,KAAK,CAAA;AAC3B,eAAO,MAAM,iBAAiB,MAAM,CAAA;AACpC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,QAAc,CAAA;AAC3C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,eAAO,MAAM,SAAS,KAAK,CAAA"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Type definitions for CommP WASM implementation
3
+ */
4
+ /** Streaming hasher interface */
5
+ export interface StreamingHasher {
6
+ /** Write bytes into the hasher */
7
+ write(bytes: Uint8Array): this;
8
+ /** Get the total bytes written */
9
+ count(): bigint;
10
+ /** Compute the digest without consuming the hasher */
11
+ digest(): PieceDigest;
12
+ /** Reset the hasher to initial state */
13
+ reset(): this;
14
+ /** Free resources */
15
+ dispose(): void;
16
+ /** Free WASM resources (alias for dispose) */
17
+ free(): void;
18
+ }
19
+ /** Piece digest result */
20
+ export interface PieceDigest {
21
+ /** Multihash code */
22
+ code: 0x1011;
23
+ /** Multihash name */
24
+ name: 'fr32-sha2-256-trunc254-padded-binary-tree';
25
+ /** Raw digest bytes (padding + height + root) */
26
+ digest: Uint8Array;
27
+ /** Full multihash bytes (code + size + digest) */
28
+ bytes: Uint8Array;
29
+ /** Tree height */
30
+ height: number;
31
+ /** 32-byte root hash */
32
+ root: Uint8Array;
33
+ /** Zero padding applied */
34
+ padding: number;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IAC9B,kCAAkC;IAClC,KAAK,IAAI,MAAM,CAAA;IACf,sDAAsD;IACtD,MAAM,IAAI,WAAW,CAAA;IACrB,wCAAwC;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,qBAAqB;IACrB,OAAO,IAAI,IAAI,CAAA;IACf,8CAA8C;IAC9C,IAAI,IAAI,IAAI,CAAA;CACb;AAED,0BAA0B;AAC1B,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,qBAAqB;IACrB,IAAI,EAAE,2CAA2C,CAAA;IACjD,iDAAiD;IACjD,MAAM,EAAE,UAAU,CAAA;IAClB,kDAAkD;IAClD,KAAK,EAAE,UAAU,CAAA;IACjB,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,wBAAwB;IACxB,IAAI,EAAE,UAAU,CAAA;IAChB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB"}
@@ -0,0 +1,17 @@
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
+ * Decodes a varint from the buffer at the given offset
11
+ *
12
+ * @param {Uint8Array} buf - Buffer to read from
13
+ * @param {number} offset - Offset to start reading
14
+ * @returns {[value: number, length: number]} - Decoded value and bytes read
15
+ */
16
+ export declare function decode(buf: Uint8Array, offset: number): [value: number, length: number];
17
+ //# sourceMappingURL=varint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"varint.d.ts","sourceRoot":"","sources":["../src/varint.js"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAJf,UAIe,EAAE,MAAM,EAHvB,MAGuB,GAFrB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAa3C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hugomrdias/commp-wasm",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Fast CommP (Filecoin Piece Commitment) WASM implementation with inline base64",
5
5
  "keywords": [
6
6
  "filecoin",
@@ -18,28 +18,31 @@
18
18
  },
19
19
  "type": "module",
20
20
  "main": "./src/index.js",
21
- "types": "./src/types.ts",
21
+ "types": "./dist/index.d.ts",
22
22
  "exports": {
23
23
  ".": {
24
- "types": "./src/types.ts",
24
+ "types": "./dist/index.d.ts",
25
25
  "import": "./src/index.js"
26
26
  }
27
27
  },
28
28
  "files": [
29
29
  "src",
30
+ "dist",
30
31
  "CHANGELOG.md"
31
32
  ],
32
33
  "devDependencies": {
33
- "@hugomrdias/commp-js": "0.1.0",
34
+ "@hugomrdias/commp-js": "0.1.1",
34
35
  "@web3-storage/data-segment": "^5.3.0",
35
- "mocha": "^12.0.2"
36
+ "mocha": "^12.0.2",
37
+ "typescript": "^7.0.2"
36
38
  },
37
39
  "scripts": {
40
+ "build": "tsc -p tsconfig.json",
38
41
  "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
42
  "build:inline": "node scripts/build-inline-wasm.js",
40
43
  "build:wasm": "pnpm build:rust && pnpm build:inline",
41
- "clean": "rm -rf pkg-bundler",
42
- "test": "mocha \"tests/**/*.test.js\"",
44
+ "clean": "rm -rf pkg-bundler dist",
45
+ "test": "tsc -p tests && mocha \"tests/**/*.test.js\"",
43
46
  "lint": "biome check ."
44
47
  }
45
48
  }
package/src/index.js CHANGED
@@ -10,7 +10,10 @@
10
10
  import { CommPHasher as WasmHasher, root as wasmRoot } from './inline/commp.js'
11
11
  import { decode as varintDecode } from './varint.js'
12
12
 
13
- /** @import { PieceDigest, StreamingHasher } from './types.js' */
13
+ /**
14
+ * @typedef {import('./types.js').PieceDigest} PieceDigest
15
+ * @typedef {import('./types.js').StreamingHasher} StreamingHasher
16
+ */
14
17
 
15
18
  /**
16
19
  * Largest slice passed to WASM per call. wasm-bindgen copies each input into
@@ -43,13 +46,7 @@ export const name = /** @type {const} */ (
43
46
  * @implements {StreamingHasher}
44
47
  */
45
48
  class Hasher {
46
- constructor() {
47
- /**
48
- * @private
49
- * @type {WasmHasher}
50
- */
51
- this.inner = new WasmHasher()
52
- }
49
+ #inner = new WasmHasher()
53
50
 
54
51
  /**
55
52
  * Get the total number of bytes written
@@ -57,7 +54,7 @@ class Hasher {
57
54
  * @returns {bigint}
58
55
  */
59
56
  count() {
60
- return BigInt(this.inner.count())
57
+ return BigInt(this.#inner.count())
61
58
  }
62
59
 
63
60
  /**
@@ -80,7 +77,7 @@ class Hasher {
80
77
  )
81
78
  }
82
79
  for (let offset = 0; offset < bytes.length; offset += CHUNK_SIZE) {
83
- this.inner.write(bytes.subarray(offset, offset + CHUNK_SIZE))
80
+ this.#inner.write(bytes.subarray(offset, offset + CHUNK_SIZE))
84
81
  }
85
82
  return this
86
83
  }
@@ -92,7 +89,7 @@ class Hasher {
92
89
  */
93
90
  digest() {
94
91
  // Format: code (varint) | size (varint) | padding (varint) | height | root
95
- const bytes = this.inner.digest()
92
+ const bytes = this.#inner.digest()
96
93
  const [, codeLength] = varintDecode(bytes, 0)
97
94
  const [, sizeLength] = varintDecode(bytes, codeLength)
98
95
  const digestStart = codeLength + sizeLength
@@ -115,7 +112,7 @@ class Hasher {
115
112
  * @returns {this}
116
113
  */
117
114
  reset() {
118
- this.inner.reset()
115
+ this.#inner.reset()
119
116
  return this
120
117
  }
121
118
 
@@ -123,14 +120,14 @@ class Hasher {
123
120
  * Dispose of resources
124
121
  */
125
122
  dispose() {
126
- this.inner.free()
123
+ this.#inner.free()
127
124
  }
128
125
 
129
126
  /**
130
127
  * Free WASM resources (alias for dispose)
131
128
  */
132
129
  free() {
133
- this.inner.free()
130
+ this.#inner.free()
134
131
  }
135
132
  }
136
133
 
@@ -200,10 +197,12 @@ export function root(payload) {
200
197
  if (payload.length <= CHUNK_SIZE) {
201
198
  return wasmRoot(payload)
202
199
  }
203
- const hasher = create()
200
+ const hasher = new WasmHasher()
204
201
  try {
205
- hasher.write(payload)
206
- return hasher.inner.root()
202
+ for (let offset = 0; offset < payload.length; offset += CHUNK_SIZE) {
203
+ hasher.write(payload.subarray(offset, offset + CHUNK_SIZE))
204
+ }
205
+ return hasher.root()
207
206
  } finally {
208
207
  hasher.free()
209
208
  }
@@ -0,0 +1,67 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ export class CommPHasher {
5
+ free(): void;
6
+ [Symbol.dispose](): void;
7
+ /**
8
+ * Create a new hasher
9
+ */
10
+ constructor();
11
+ /**
12
+ * Get just the 32-byte CommP root hash
13
+ *
14
+ * Returns the raw Merkle root without multihash encoding.
15
+ * Use `digest()` if you need the full multihash with metadata.
16
+ */
17
+ root(): Uint8Array;
18
+ /**
19
+ * Get bytes written count
20
+ */
21
+ count(): bigint;
22
+ /**
23
+ * Reset the hasher for reuse
24
+ */
25
+ reset(): void;
26
+ /**
27
+ * Write bytes into the hasher
28
+ *
29
+ * Throws a `RangeError` (without changing the hasher) if the total would
30
+ * exceed `MAX_PAYLOAD_SIZE`.
31
+ */
32
+ write(bytes: Uint8Array): void;
33
+ /**
34
+ * Get the full multihash-encoded digest
35
+ *
36
+ * Returns: [code (varint 0x1011), size (varint), padding (varint), height (u8), root (32 bytes)]
37
+ *
38
+ * - `code`: 0x1011 = "fr32-sha256-trunc254-padded-binary-tree" multihash identifier
39
+ * - `size`: total digest size (padding_len + 1 + 32)
40
+ * - `padding`: bytes of zero-padding added to reach next power-of-two piece size
41
+ * - `height`: tree height (log2 of piece size / 32)
42
+ * - `root`: 32-byte Merkle root
43
+ */
44
+ digest(): Uint8Array;
45
+ /**
46
+ * Get the tree height
47
+ */
48
+ height(): number;
49
+ }
50
+
51
+ /**
52
+ * One-shot digest: returns full multihash-encoded CommP
53
+ *
54
+ * Format: [code (varint 0x1011), size (varint), padding (varint), height (u8), root (32 bytes)]
55
+ *
56
+ * Use this when you need the complete Filecoin piece commitment with metadata.
57
+ * The multihash code 0x1011 identifies this as "fr32-sha256-trunc254-padded-binary-tree".
58
+ */
59
+ export function digest(data: Uint8Array): Uint8Array;
60
+
61
+ /**
62
+ * One-shot root: returns just the 32-byte CommP root hash
63
+ *
64
+ * Use this when you only need the raw hash without multihash encoding.
65
+ * This is the Merkle root of the FR32-padded, SHA256-hashed binary tree.
66
+ */
67
+ export function root(data: Uint8Array): Uint8Array;