@cap.js/widget 0.1.57 → 0.1.59

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/src/worker.js CHANGED
@@ -3,6 +3,19 @@
3
3
  if (!self.CAP_SILENT) console[method]("[cap worker]", ...args);
4
4
  };
5
5
 
6
+ const HASHWX_CLOCK_EVERY = 256;
7
+ const HASHWX_YIELD_MS = 16;
8
+ const HASHWX_PROGRESS_MS = 150;
9
+ let stopRequested = false;
10
+ const yieldChannel =
11
+ typeof MessageChannel === "function" ? new MessageChannel() : null;
12
+ const macrotask = () =>
13
+ new Promise((resolve) => {
14
+ if (!yieldChannel) return setTimeout(resolve, 0);
15
+ yieldChannel.port1.onmessage = () => resolve();
16
+ yieldChannel.port2.postMessage(0);
17
+ });
18
+
6
19
  const solveFallback = async ({ salt, target }) => {
7
20
  let nonce = 0;
8
21
  const batchSize = 50000;
@@ -19,7 +32,8 @@
19
32
  targetBytes[k] = parseInt(paddedTarget.substring(k * 2, k * 2 + 2), 16);
20
33
  }
21
34
 
22
- const partialMask = remainingBits > 0 ? (0xff << (8 - remainingBits)) & 0xff : 0;
35
+ const partialMask =
36
+ remainingBits > 0 ? (0xff << (8 - remainingBits)) & 0xff : 0;
23
37
 
24
38
  while (true) {
25
39
  try {
@@ -41,7 +55,10 @@
41
55
  }
42
56
 
43
57
  if (matches && remainingBits > 0) {
44
- if ((hashBytes[fullBytes] & partialMask) !== (targetBytes[fullBytes] & partialMask)) {
58
+ if (
59
+ (hashBytes[fullBytes] & partialMask) !==
60
+ (targetBytes[fullBytes] & partialMask)
61
+ ) {
45
62
  matches = false;
46
63
  }
47
64
  }
@@ -54,7 +71,7 @@
54
71
  nonce++;
55
72
  }
56
73
  } catch (error) {
57
- wlog("error","fallback solver crashed:", error.message || error);
74
+ wlog("error", "fallback solver crashed:", error.message || error);
58
75
  self.postMessage({
59
76
  found: false,
60
77
  error: error.message,
@@ -65,8 +82,8 @@
65
82
  };
66
83
 
67
84
  const solveRsw = (data) => {
68
- const N = BigInt("0x" + data.N);
69
- let y = BigInt("0x" + data.x);
85
+ const N = BigInt(`0x${data.N}`);
86
+ let y = BigInt(`0x${data.x}`);
70
87
  const t = data.t | 0;
71
88
  const chunk = Math.max(64, Math.floor(t / 50));
72
89
  const t0 = performance.now();
@@ -82,11 +99,246 @@
82
99
  });
83
100
  };
84
101
 
85
- if (typeof WebAssembly !== "object" || typeof WebAssembly?.instantiate !== "function") {
86
- wlog("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)");
102
+ const SHA_K = new Uint32Array([
103
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
104
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
105
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
106
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
107
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
108
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
109
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
110
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
111
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
112
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
113
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
114
+ ]);
115
+
116
+ const sha256Into = (bytes, out) => {
117
+ const len = bytes.length;
118
+ const blocks = ((len + 8) >> 6) + 1;
119
+ const padded = new Uint8Array(blocks << 6);
120
+ padded.set(bytes);
121
+ padded[len] = 0x80;
122
+ const bitLen = len * 8;
123
+ const dv = new DataView(padded.buffer);
124
+ dv.setUint32(padded.length - 4, bitLen >>> 0, false);
125
+ dv.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000), false);
126
+
127
+ let h0 = 0x6a09e667,
128
+ h1 = 0xbb67ae85,
129
+ h2 = 0x3c6ef372,
130
+ h3 = 0xa54ff53a;
131
+ let h4 = 0x510e527f,
132
+ h5 = 0x9b05688c,
133
+ h6 = 0x1f83d9ab,
134
+ h7 = 0x5be0cd19;
135
+ const w = new Uint32Array(64);
136
+
137
+ for (let b = 0; b < blocks; b++) {
138
+ const off = b << 6;
139
+ for (let i = 0; i < 16; i++) w[i] = dv.getUint32(off + (i << 2), false);
140
+ for (let i = 16; i < 64; i++) {
141
+ const x = w[i - 15],
142
+ y = w[i - 2];
143
+ const s0 =
144
+ ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
145
+ const s1 =
146
+ ((y >>> 17) | (y << 15)) ^ ((y >>> 19) | (y << 13)) ^ (y >>> 10);
147
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
148
+ }
149
+ let a = h0,
150
+ bb = h1,
151
+ c = h2,
152
+ d = h3,
153
+ e = h4,
154
+ f = h5,
155
+ g = h6,
156
+ h = h7;
157
+ for (let i = 0; i < 64; i++) {
158
+ const S1 =
159
+ ((e >>> 6) | (e << 26)) ^
160
+ ((e >>> 11) | (e << 21)) ^
161
+ ((e >>> 25) | (e << 7));
162
+ const ch = (e & f) ^ (~e & g);
163
+ const t1 = (h + S1 + ch + SHA_K[i] + w[i]) >>> 0;
164
+ const S0 =
165
+ ((a >>> 2) | (a << 30)) ^
166
+ ((a >>> 13) | (a << 19)) ^
167
+ ((a >>> 22) | (a << 10));
168
+ const maj = (a & bb) ^ (a & c) ^ (bb & c);
169
+ const t2 = (S0 + maj) >>> 0;
170
+ h = g;
171
+ g = f;
172
+ f = e;
173
+ e = (d + t1) >>> 0;
174
+ d = c;
175
+ c = bb;
176
+ bb = a;
177
+ a = (t1 + t2) >>> 0;
178
+ }
179
+ h0 = (h0 + a) >>> 0;
180
+ h1 = (h1 + bb) >>> 0;
181
+ h2 = (h2 + c) >>> 0;
182
+ h3 = (h3 + d) >>> 0;
183
+ h4 = (h4 + e) >>> 0;
184
+ h5 = (h5 + f) >>> 0;
185
+ h6 = (h6 + g) >>> 0;
186
+ h7 = (h7 + h) >>> 0;
187
+ }
188
+
189
+ const odv = new DataView(out.buffer, out.byteOffset, 32);
190
+ odv.setUint32(0, h0, false);
191
+ odv.setUint32(4, h1, false);
192
+ odv.setUint32(8, h2, false);
193
+ odv.setUint32(12, h3, false);
194
+ odv.setUint32(16, h4, false);
195
+ odv.setUint32(20, h5, false);
196
+ odv.setUint32(24, h6, false);
197
+ odv.setUint32(28, h7, false);
198
+ };
199
+
200
+ let hashwxRuntime = null;
201
+
202
+ const getHashwxRuntime = (hashwxModule) => {
203
+ if (hashwxRuntime) return hashwxRuntime;
204
+
205
+ const instance = new WebAssembly.Instance(hashwxModule, {});
206
+ const w = instance.exports;
207
+ if (w._initialize) w._initialize();
208
+
209
+ let compiled = true;
210
+ let ctx = w.hashwx_alloc(1);
211
+ if (ctx === -1 || ctx === 0) {
212
+ compiled = false;
213
+ ctx = w.hashwx_alloc(0);
214
+ }
215
+ if (ctx <= 0) throw new Error("hashwx_alloc failed");
216
+
217
+ hashwxRuntime = {
218
+ w,
219
+ ctx,
220
+ compiled,
221
+ seedPtr: w.hashwx_seed(ctx),
222
+ regPtr: compiled ? w.hashwx_registers(ctx) : 0,
223
+ memPtr: compiled ? w.hashwx_memory(ctx) : 0,
224
+ };
225
+ return hashwxRuntime;
226
+ };
227
+
228
+ const solveHashwx = async (data) => {
229
+ const { c, d, n, workerIndex, workerCount, hashwxModule } = data;
230
+ if (!Number.isInteger(n) || n < 1 || !Number.isInteger(d) || d < 1) {
231
+ throw new Error("malformed hashwx challenge payload");
232
+ }
233
+ const noncesPerHash = n >>> 0;
234
+ const target = ((1n << 64n) - 1n) / BigInt(d);
235
+ stopRequested = false;
236
+
237
+ const { w, ctx, compiled, seedPtr, regPtr, memPtr } =
238
+ getHashwxRuntime(hashwxModule);
239
+
240
+ const challenge = new Uint8Array(32);
241
+ for (let i = 0; i < 32; i++)
242
+ challenge[i] = parseInt(c.slice(i * 2, i * 2 + 2), 16);
243
+ const seedInput = new Uint8Array(40);
244
+ seedInput.set(challenge, 0);
245
+ const seedOut = new Uint8Array(32);
246
+
247
+ const t0 = performance.now();
248
+ let hashes = 0;
249
+ let lastYield = t0;
250
+ let lastReport = t0;
251
+
252
+ try {
253
+ for (let block = workerIndex; ; block += workerCount) {
254
+ let rest = block;
255
+ for (let i = 0; i < 8; i++) {
256
+ seedInput[32 + i] = rest & 0xff;
257
+ rest = Math.floor(rest / 256);
258
+ }
259
+ sha256Into(seedInput, seedOut);
260
+ new Uint8Array(w.memory.buffer, seedPtr, 32).set(seedOut);
261
+ w.hashwx_make(ctx, seedPtr);
262
+
263
+ let side = null;
264
+ if (compiled) {
265
+ const codePtr = w.hashwx_module(ctx);
266
+ const codeSize = w.hashwx_module_size(ctx);
267
+ const bytes = new Uint8Array(
268
+ w.memory.buffer,
269
+ codePtr,
270
+ codeSize,
271
+ ).slice();
272
+ side = new WebAssembly.Instance(new WebAssembly.Module(bytes), {
273
+ env: { memory: w.memory },
274
+ }).exports.exec;
275
+ }
276
+
277
+ const base = BigInt(block) * BigInt(noncesPerHash);
278
+ for (let k = 0; k < noncesPerHash; k++) {
279
+ const nonce = base + BigInt(k);
280
+ let hash;
281
+ if (compiled) {
282
+ w.hashwx_exec_begin(ctx, nonce);
283
+ side(regPtr, memPtr);
284
+ hash = BigInt.asUintN(64, w.hashwx_exec_final(ctx));
285
+ } else {
286
+ hash = BigInt.asUintN(64, w.hashwx_exec(ctx, nonce));
287
+ }
288
+ hashes++;
289
+ if (hash <= target) {
290
+ self.postMessage({
291
+ found: true,
292
+ nonce: nonce.toString(),
293
+ hashes,
294
+ compiled,
295
+ durationMs: (performance.now() - t0).toFixed(2),
296
+ });
297
+ return;
298
+ }
299
+ if ((hashes & (HASHWX_CLOCK_EVERY - 1)) === 0) {
300
+ const now = performance.now();
301
+ if (now - lastYield >= HASHWX_YIELD_MS) {
302
+ if (now - lastReport >= HASHWX_PROGRESS_MS) {
303
+ lastReport = now;
304
+ self.postMessage({ progress: hashes });
305
+ }
306
+ await macrotask();
307
+ lastYield = performance.now();
308
+ if (stopRequested) {
309
+ return self.postMessage({ found: false, error: "stopped" });
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ } catch (error) {
316
+ hashwxRuntime = null;
317
+ throw error;
318
+ }
319
+ };
320
+
321
+ if (
322
+ typeof WebAssembly !== "object" ||
323
+ typeof WebAssembly?.instantiate !== "function"
324
+ ) {
325
+ wlog(
326
+ "warn",
327
+ "WebAssembly unavailable, using JS fallback solver (significantly slower)",
328
+ );
87
329
 
88
330
  self.onmessage = async ({ data }) => {
331
+ if (data?.kind === "stop") {
332
+ stopRequested = true;
333
+ return;
334
+ }
89
335
  if (data?.kind === "rsw") return solveRsw(data);
336
+ if (data?.kind === "hashwx") {
337
+ return self.postMessage({
338
+ found: false,
339
+ error: "hashwx requires WebAssembly",
340
+ });
341
+ }
90
342
  return solveFallback({ salt: data.salt, target: data.target });
91
343
  };
92
344
 
@@ -102,7 +354,10 @@
102
354
  let cachedUint8ArrayMemory = null;
103
355
 
104
356
  const getMemory = () => {
105
- if (cachedUint8ArrayMemory === null || cachedUint8ArrayMemory.byteLength === 0) {
357
+ if (
358
+ cachedUint8ArrayMemory === null ||
359
+ cachedUint8ArrayMemory.byteLength === 0
360
+ ) {
106
361
  cachedUint8ArrayMemory = new Uint8Array(wasm.memory.buffer);
107
362
  }
108
363
  return cachedUint8ArrayMemory;
@@ -164,33 +419,62 @@
164
419
  if (wasm.__wbindgen_start) wasm.__wbindgen_start();
165
420
 
166
421
  solve_pow_function = (salt, target) => {
167
- const saltPtr = passStringToWasm(salt, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
422
+ const saltPtr = passStringToWasm(
423
+ salt,
424
+ wasm.__wbindgen_malloc,
425
+ wasm.__wbindgen_realloc,
426
+ );
168
427
  const saltLen = WASM_VECTOR_LEN;
169
- const targetPtr = passStringToWasm(target, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
428
+ const targetPtr = passStringToWasm(
429
+ target,
430
+ wasm.__wbindgen_malloc,
431
+ wasm.__wbindgen_realloc,
432
+ );
170
433
  const targetLen = WASM_VECTOR_LEN;
171
- return BigInt.asUintN(64, wasm.solve_pow(saltPtr, saltLen, targetPtr, targetLen));
434
+ return BigInt.asUintN(
435
+ 64,
436
+ wasm.solve_pow(saltPtr, saltLen, targetPtr, targetLen),
437
+ );
172
438
  };
173
439
 
174
440
  return true;
175
441
  } catch (e) {
176
- wlog("error","wasm init failed:", e.message || e);
442
+ wlog("error", "wasm init failed:", e.message || e);
177
443
  return false;
178
444
  }
179
445
  };
180
446
 
181
447
  self.onmessage = async ({ data }) => {
448
+ if (data?.kind === "stop") {
449
+ stopRequested = true;
450
+ return;
451
+ }
182
452
  if (data?.kind === "rsw") return solveRsw(data);
453
+ if (data?.kind === "hashwx") {
454
+ try {
455
+ return await solveHashwx(data);
456
+ } catch (error) {
457
+ wlog("error", "hashwx solver threw:", error.message || error);
458
+ return self.postMessage({
459
+ found: false,
460
+ error: error.message || String(error),
461
+ });
462
+ }
463
+ }
183
464
  const { salt, target, wasmModule } = data;
184
- if (wasmModule instanceof WebAssembly.Module && solve_pow_function === null) {
465
+ if (
466
+ wasmModule instanceof WebAssembly.Module &&
467
+ solve_pow_function === null
468
+ ) {
185
469
  const ok = initFromModule(wasmModule);
186
470
  if (!ok) {
187
- wlog("warn","wasm init failed, falling back to JS solver");
471
+ wlog("warn", "wasm init failed, falling back to JS solver");
188
472
  return solveFallback({ salt, target });
189
473
  }
190
474
  }
191
475
 
192
476
  if (solve_pow_function === null) {
193
- wlog("warn","no wasm module provided, falling back to JS solver");
477
+ wlog("warn", "no wasm module provided, falling back to JS solver");
194
478
  return solveFallback({ salt, target });
195
479
  }
196
480
 
@@ -205,7 +489,7 @@
205
489
  durationMs: (endTime - startTime).toFixed(2),
206
490
  });
207
491
  } catch (error) {
208
- wlog("error","solve_pow threw:", error.message || error);
492
+ wlog("error", "solve_pow threw:", error.message || error);
209
493
 
210
494
  self.postMessage({
211
495
  found: false,