@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 +35 -0
- package/package.json +45 -0
- package/src/index.js +226 -0
- package/src/inline/commp.js +13 -0
- package/src/inline/commp_bg.js +269 -0
- package/src/inline/commp_bg.wasm.js +29 -0
- package/src/types.ts +37 -0
- package/src/varint.js +28 -0
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
|
+
}
|