ox 0.14.18 → 0.14.19

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/_cjs/tempo/TxEnvelopeTempo.js.map +1 -1
  3. package/_cjs/tempo/VirtualMaster.js +192 -13
  4. package/_cjs/tempo/VirtualMaster.js.map +1 -1
  5. package/_cjs/tempo/index.js.map +1 -1
  6. package/_cjs/tempo/internal/mine.wasm.js +6 -0
  7. package/_cjs/tempo/internal/mine.wasm.js.map +1 -0
  8. package/_cjs/tempo/internal/virtualMasterPool.js +186 -0
  9. package/_cjs/tempo/internal/virtualMasterPool.js.map +1 -0
  10. package/_cjs/version.js +1 -1
  11. package/_esm/tempo/TxEnvelopeTempo.js +6 -3
  12. package/_esm/tempo/TxEnvelopeTempo.js.map +1 -1
  13. package/_esm/tempo/VirtualMaster.js +305 -22
  14. package/_esm/tempo/VirtualMaster.js.map +1 -1
  15. package/_esm/tempo/index.js +4 -2
  16. package/_esm/tempo/index.js.map +1 -1
  17. package/_esm/tempo/internal/mine.wasm.js +15 -0
  18. package/_esm/tempo/internal/mine.wasm.js.map +1 -0
  19. package/_esm/tempo/internal/virtualMasterPool.js +216 -0
  20. package/_esm/tempo/internal/virtualMasterPool.js.map +1 -0
  21. package/_esm/version.js +1 -1
  22. package/_types/tempo/TxEnvelopeTempo.d.ts +6 -3
  23. package/_types/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  24. package/_types/tempo/VirtualMaster.d.ts +92 -10
  25. package/_types/tempo/VirtualMaster.d.ts.map +1 -1
  26. package/_types/tempo/index.d.ts +4 -2
  27. package/_types/tempo/index.d.ts.map +1 -1
  28. package/_types/tempo/internal/mine.wasm.d.ts +5 -0
  29. package/_types/tempo/internal/mine.wasm.d.ts.map +1 -0
  30. package/_types/tempo/internal/virtualMasterPool.d.ts +46 -0
  31. package/_types/tempo/internal/virtualMasterPool.d.ts.map +1 -0
  32. package/_types/version.d.ts +1 -1
  33. package/package.json +1 -1
  34. package/tempo/TxEnvelopeTempo.ts +6 -3
  35. package/tempo/VirtualMaster.test.ts +77 -0
  36. package/tempo/VirtualMaster.ts +431 -23
  37. package/tempo/index.ts +5 -2
  38. package/tempo/internal/mine.c +182 -0
  39. package/tempo/internal/mine.wasm.ts +17 -0
  40. package/tempo/internal/virtualMasterPool.ts +254 -0
  41. package/version.ts +1 -1
@@ -0,0 +1,182 @@
1
+ // TIP-1022 salt mining — isomorphic WASM (Node + browser).
2
+ // Specialized single-block keccak256 for 52-byte input.
3
+ //
4
+ // Memory layout at offset 1024:
5
+ // [0..19] address (set by JS)
6
+ // [20..51] salt (set by JS, incremented in-place)
7
+ // [52..83] hash out (written on match)
8
+
9
+ typedef unsigned char uint8_t;
10
+ typedef unsigned int uint32_t;
11
+ typedef unsigned long long uint64_t;
12
+
13
+ #define DATA_OFFSET 1024
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Keccak-f[1600] — fully unrolled, native uint64_t → wasm i64.
17
+ // Based on XKCP / hash-wasm structure.
18
+ // ---------------------------------------------------------------------------
19
+
20
+ #define ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
21
+
22
+ static const uint64_t RC[24] = {
23
+ 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
24
+ 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
25
+ 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
26
+ 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
27
+ 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
28
+ 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
29
+ 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
30
+ 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL,
31
+ };
32
+
33
+ // Theta — fully unrolled column parity + diffusion
34
+ #define XORED(i) (A[(i)] ^ A[(i)+5] ^ A[(i)+10] ^ A[(i)+15] ^ A[(i)+20])
35
+
36
+ static inline void theta(uint64_t *A) {
37
+ uint64_t D[5];
38
+ D[0] = ROTL64(XORED(1), 1) ^ XORED(4);
39
+ D[1] = ROTL64(XORED(2), 1) ^ XORED(0);
40
+ D[2] = ROTL64(XORED(3), 1) ^ XORED(1);
41
+ D[3] = ROTL64(XORED(4), 1) ^ XORED(2);
42
+ D[4] = ROTL64(XORED(0), 1) ^ XORED(3);
43
+ A[ 0]^=D[0]; A[ 1]^=D[1]; A[ 2]^=D[2]; A[ 3]^=D[3]; A[ 4]^=D[4];
44
+ A[ 5]^=D[0]; A[ 6]^=D[1]; A[ 7]^=D[2]; A[ 8]^=D[3]; A[ 9]^=D[4];
45
+ A[10]^=D[0]; A[11]^=D[1]; A[12]^=D[2]; A[13]^=D[3]; A[14]^=D[4];
46
+ A[15]^=D[0]; A[16]^=D[1]; A[17]^=D[2]; A[18]^=D[3]; A[19]^=D[4];
47
+ A[20]^=D[0]; A[21]^=D[1]; A[22]^=D[2]; A[23]^=D[3]; A[24]^=D[4];
48
+ }
49
+
50
+ // Rho — explicit per-lane rotations with compile-time constants
51
+ static inline void rho(uint64_t *A) {
52
+ A[ 1] = ROTL64(A[ 1], 1); A[ 2] = ROTL64(A[ 2], 62);
53
+ A[ 3] = ROTL64(A[ 3], 28); A[ 4] = ROTL64(A[ 4], 27);
54
+ A[ 5] = ROTL64(A[ 5], 36); A[ 6] = ROTL64(A[ 6], 44);
55
+ A[ 7] = ROTL64(A[ 7], 6); A[ 8] = ROTL64(A[ 8], 55);
56
+ A[ 9] = ROTL64(A[ 9], 20); A[10] = ROTL64(A[10], 3);
57
+ A[11] = ROTL64(A[11], 10); A[12] = ROTL64(A[12], 43);
58
+ A[13] = ROTL64(A[13], 25); A[14] = ROTL64(A[14], 39);
59
+ A[15] = ROTL64(A[15], 41); A[16] = ROTL64(A[16], 45);
60
+ A[17] = ROTL64(A[17], 15); A[18] = ROTL64(A[18], 21);
61
+ A[19] = ROTL64(A[19], 8); A[20] = ROTL64(A[20], 18);
62
+ A[21] = ROTL64(A[21], 2); A[22] = ROTL64(A[22], 61);
63
+ A[23] = ROTL64(A[23], 56); A[24] = ROTL64(A[24], 14);
64
+ }
65
+
66
+ // Pi — single-temporary rotation chain (no scratch buffer)
67
+ static inline void pi(uint64_t *A) {
68
+ uint64_t A1 = A[1];
69
+ A[ 1]=A[ 6]; A[ 6]=A[ 9]; A[ 9]=A[22]; A[22]=A[14]; A[14]=A[20];
70
+ A[20]=A[ 2]; A[ 2]=A[12]; A[12]=A[13]; A[13]=A[19]; A[19]=A[23];
71
+ A[23]=A[15]; A[15]=A[ 4]; A[ 4]=A[24]; A[24]=A[21]; A[21]=A[ 8];
72
+ A[ 8]=A[16]; A[16]=A[ 5]; A[ 5]=A[ 3]; A[ 3]=A[18]; A[18]=A[17];
73
+ A[17]=A[11]; A[11]=A[ 7]; A[ 7]=A[10]; A[10]=A1;
74
+ }
75
+
76
+ // Chi — unrolled nonlinear step
77
+ #define CHI_ROW(i) { \
78
+ uint64_t a0 = A[(i)], a1 = A[(i)+1]; \
79
+ A[(i) ] ^= ~a1 & A[(i)+2]; \
80
+ A[(i)+1] ^= ~A[(i)+2] & A[(i)+3]; \
81
+ A[(i)+2] ^= ~A[(i)+3] & A[(i)+4]; \
82
+ A[(i)+3] ^= ~A[(i)+4] & a0; \
83
+ A[(i)+4] ^= ~a0 & a1; \
84
+ }
85
+
86
+ static inline void chi(uint64_t *A) {
87
+ CHI_ROW(0); CHI_ROW(5); CHI_ROW(10); CHI_ROW(15); CHI_ROW(20);
88
+ }
89
+
90
+ static void keccak_f1600(uint64_t *A) {
91
+ for (int r = 0; r < 24; r++) {
92
+ theta(A); rho(A); pi(A); chi(A);
93
+ A[0] ^= RC[r];
94
+ }
95
+ }
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // Helpers
99
+ // ---------------------------------------------------------------------------
100
+
101
+ static inline uint64_t load64_le(const uint8_t *p) {
102
+ return (uint64_t)p[0] | ((uint64_t)p[1] << 8) |
103
+ ((uint64_t)p[2] <<16)| ((uint64_t)p[3] << 24) |
104
+ ((uint64_t)p[4] <<32)| ((uint64_t)p[5] << 40) |
105
+ ((uint64_t)p[6] <<48)| ((uint64_t)p[7] << 56);
106
+ }
107
+
108
+ static inline void store64_le(uint8_t *p, uint64_t v) {
109
+ p[0]=(uint8_t)v; p[1]=(uint8_t)(v>>8); p[2]=(uint8_t)(v>>16); p[3]=(uint8_t)(v>>24);
110
+ p[4]=(uint8_t)(v>>32); p[5]=(uint8_t)(v>>40); p[6]=(uint8_t)(v>>48); p[7]=(uint8_t)(v>>56);
111
+ }
112
+
113
+ static inline uint32_t load32_le(const uint8_t *p) {
114
+ return (uint32_t)p[0] | ((uint32_t)p[1]<<8) | ((uint32_t)p[2]<<16) | ((uint32_t)p[3]<<24);
115
+ }
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // Mining entry point
119
+ // ---------------------------------------------------------------------------
120
+
121
+ __attribute__((export_name("mine")))
122
+ int mine(int count) {
123
+ uint8_t *mem = (uint8_t *)DATA_OFFSET;
124
+ uint8_t *addr = mem; // 20 bytes
125
+ uint8_t *salt = mem + 20; // 32 bytes
126
+ uint8_t *hout = mem + 52; // 32 bytes
127
+
128
+ // Pre-build base state for 52-byte keccak256 (one block, rate=136).
129
+ // Block = [address(20) | salt(32) | 0x01 | zeros | 0x80]
130
+ // Only lanes 0..6 are non-zero from the message, plus padding in lanes 6 & 16.
131
+ uint64_t base[25];
132
+ for (int i = 0; i < 25; i++) base[i] = 0;
133
+
134
+ // Load address into lanes 0..2 (bytes 0..23, only 0..19 used)
135
+ uint8_t buf[24];
136
+ for (int i = 0; i < 20; i++) buf[i] = addr[i];
137
+ for (int i = 20; i < 24; i++) buf[i] = 0;
138
+ base[0] = load64_le(buf);
139
+ base[1] = load64_le(buf + 8);
140
+ base[2] = load64_le(buf + 16);
141
+
142
+ // Keccak padding: byte 52 = 0x01, byte 135 = 0x80
143
+ // Lane 6 (bytes 48..55): byte 52 = lane offset 4 → bit 32
144
+ base[6] = (uint64_t)0x01 << 32;
145
+ // Lane 16 (bytes 128..135): byte 135 = lane offset 7 → bit 56
146
+ base[16] = (uint64_t)0x80 << 56;
147
+
148
+ for (int iter = 0; iter < count; iter++) {
149
+ // Copy base, XOR salt.
150
+ // Salt occupies bytes 20..51 → lanes 2..6.
151
+ uint64_t A[25];
152
+ for (int i = 0; i < 25; i++) A[i] = base[i];
153
+
154
+ // Lane 2 (bytes 16..23): upper 4 bytes = salt[0..3]
155
+ A[2] ^= (uint64_t)load32_le(salt) << 32;
156
+ // Lane 3 (bytes 24..31): salt[4..11]
157
+ A[3] ^= load64_le(salt + 4);
158
+ // Lane 4 (bytes 32..39): salt[12..19]
159
+ A[4] ^= load64_le(salt + 12);
160
+ // Lane 5 (bytes 40..47): salt[20..27]
161
+ A[5] ^= load64_le(salt + 20);
162
+ // Lane 6 (bytes 48..55): lower 4 bytes = salt[28..31]
163
+ A[6] ^= (uint64_t)load32_le(salt + 28);
164
+
165
+ keccak_f1600(A);
166
+
167
+ // PoW check: first 4 bytes = low 32 bits of lane 0 must be zero.
168
+ if ((uint32_t)A[0] == 0) {
169
+ for (int i = 0; i < 4; i++)
170
+ store64_le(hout + i * 8, A[i]);
171
+ return 1;
172
+ }
173
+
174
+ // Increment big-endian salt.
175
+ for (int i = 31; i >= 0; i--) {
176
+ if (salt[i] < 0xFF) { salt[i]++; break; }
177
+ salt[i] = 0;
178
+ }
179
+ }
180
+
181
+ return 0;
182
+ }
@@ -0,0 +1,17 @@
1
+ // Embedded TIP-1022 WASM keccak256 salt miner (compiled from mine.c).
2
+ //
3
+ // Memory layout at offset 1024:
4
+ // [0..19] address (20 bytes, set by JS)
5
+ // [20..51] salt (32 bytes, set/read by JS, incremented in-place)
6
+ // [52..83] hash out (32 bytes, written on match)
7
+ //
8
+ // Exported: mine(count: i32) -> i32 — returns 1 if found, 0 if not.
9
+ //
10
+ // Generated by: pnpm tsx scripts/build-mine-wasm.ts
11
+
12
+ /** Base64-encoded WASM binary for the TIP-1022 salt miner. */
13
+ export const wasmBase64 =
14
+ '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'
15
+
16
+ /** Byte offset in WASM linear memory where mining I/O begins. */
17
+ export const dataOffset = 1024
@@ -0,0 +1,254 @@
1
+ import * as Errors from '../../core/Errors.js'
2
+
3
+ /** Message sent from a mining worker to the main thread. */
4
+ export type Message =
5
+ | { type: 'done' }
6
+ | { type: 'error'; message: string }
7
+ | {
8
+ type: 'found'
9
+ result: {
10
+ /** The 4-byte master identifier. */
11
+ masterId: string
12
+ /** The full 32-byte registration hash. */
13
+ registrationHash: string
14
+ /** The discovered 32-byte salt. */
15
+ salt: string
16
+ }
17
+ }
18
+ | { type: 'progress'; attempts: number }
19
+
20
+ /** A platform-agnostic worker pool for parallel salt mining. */
21
+ export type Pool = {
22
+ spawn(
23
+ index: number,
24
+ onMessage: (msg: Message) => void,
25
+ onError: (err: unknown) => void,
26
+ ): { postMessage(data: unknown): void; terminate(): void }
27
+ }
28
+
29
+ let cachedPool: Pool | undefined
30
+
31
+ /**
32
+ * Whether the current runtime is Node.js.
33
+ *
34
+ * @internal
35
+ */
36
+ const isNode =
37
+ typeof globalThis.process !== 'undefined' &&
38
+ typeof globalThis.process.versions?.node === 'string'
39
+
40
+ /**
41
+ * Resolves the best available worker pool for the current runtime.
42
+ *
43
+ * @internal
44
+ */
45
+ export async function resolve(): Promise<Pool | undefined> {
46
+ if (cachedPool) return cachedPool
47
+ cachedPool = isNode ? await resolveNode() : await resolveBrowser()
48
+ return cachedPool
49
+ }
50
+
51
+ /**
52
+ * Creates a worker pool backed by Node.js `worker_threads`.
53
+ *
54
+ * @internal
55
+ */
56
+ export async function resolveNode(): Promise<Pool | undefined> {
57
+ const { Worker } = await import('node:worker_threads')
58
+ const { wasmBase64 } = await import('./mine.wasm.js')
59
+ const workerSource = getNodeWorkerSource()
60
+
61
+ return {
62
+ spawn(index, onMessage, onError) {
63
+ const worker = new Worker(workerSource, {
64
+ eval: true,
65
+ workerData: {
66
+ wasmBase64,
67
+ workerIndex: index,
68
+ },
69
+ })
70
+ worker.on('message', (msg: Message) => onMessage(msg))
71
+ worker.on('error', (err) => onError(err))
72
+ worker.on('exit', (code) => {
73
+ if (code !== 0)
74
+ onError(
75
+ new Errors.BaseError(
76
+ `A salt mining worker exited with code "${code}".`,
77
+ ),
78
+ )
79
+ })
80
+ return {
81
+ postMessage(data) {
82
+ worker.postMessage(data)
83
+ },
84
+ terminate() {
85
+ void worker.terminate().catch(() => {})
86
+ },
87
+ }
88
+ },
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Creates a worker pool backed by browser `Worker` with Blob URLs.
94
+ *
95
+ * @internal
96
+ */
97
+ export async function resolveBrowser(): Promise<Pool | undefined> {
98
+ if (typeof globalThis.Worker === 'undefined') return undefined
99
+ if (typeof globalThis.Blob === 'undefined') return undefined
100
+
101
+ const { wasmBase64 } = await import('./mine.wasm.js')
102
+ const source = getBrowserWorkerSource(wasmBase64)
103
+ const blob = new Blob([source], { type: 'application/javascript' })
104
+ const url = URL.createObjectURL(blob)
105
+
106
+ return {
107
+ spawn(_index, onMessage, onError) {
108
+ const worker = new globalThis.Worker(url)
109
+ worker.onmessage = (e: MessageEvent<Message>) => onMessage(e.data)
110
+ worker.onerror = (e) => onError(e.error)
111
+ return {
112
+ postMessage(data) {
113
+ worker.postMessage(data)
114
+ },
115
+ terminate() {
116
+ worker.terminate()
117
+ },
118
+ }
119
+ },
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Returns the inline JavaScript source for a browser Web Worker.
125
+ *
126
+ * @internal
127
+ */
128
+ function getBrowserWorkerSource(wasmBase64: string): string {
129
+ return `
130
+ 'use strict'
131
+
132
+ ${getWorkerMineLoop()}
133
+
134
+ var binary = Uint8Array.from(atob(${JSON.stringify(wasmBase64)}), function(c) { return c.charCodeAt(0) })
135
+
136
+ WebAssembly.instantiate(binary).then(function(result) {
137
+ var wasm = result.instance.exports
138
+ var mem = new Uint8Array(wasm.memory.buffer)
139
+
140
+ self.onmessage = function(e) {
141
+ if (e.data.type !== 'start') return
142
+ mineLoop(e.data, wasm, mem, function(msg) { self.postMessage(msg) })
143
+ }
144
+ }).catch(function(error) {
145
+ self.postMessage({ type: 'error', message: error && error.message || String(error) })
146
+ })
147
+ `
148
+ }
149
+
150
+ /**
151
+ * Returns the eval'd JavaScript source for a Node.js `worker_threads` worker.
152
+ *
153
+ * @internal
154
+ */
155
+ function getNodeWorkerSource(): string {
156
+ return `
157
+ 'use strict'
158
+ var { parentPort, workerData } = require('node:worker_threads')
159
+
160
+ ${getWorkerMineLoop()}
161
+
162
+ async function main() {
163
+ var binary = Buffer.from(workerData.wasmBase64, 'base64')
164
+ var { instance } = await WebAssembly.instantiate(binary)
165
+ var wasm = instance.exports
166
+ var mem = new Uint8Array(wasm.memory.buffer)
167
+
168
+ parentPort.on('message', function(data) {
169
+ if (data.type !== 'start') return
170
+ mineLoop(data, wasm, mem, function(msg) { parentPort.postMessage(msg) })
171
+ })
172
+ }
173
+
174
+ main().catch(function(error) {
175
+ parentPort.postMessage({ type: 'error', message: error && error.message || String(error) })
176
+ })
177
+ `
178
+ }
179
+
180
+ /**
181
+ * Returns the shared WASM mining loop source used by both Node and browser workers.
182
+ *
183
+ * @internal
184
+ */
185
+ function getWorkerMineLoop(): string {
186
+ return `
187
+ var dataOffset = 1024
188
+
189
+ function hexToBytes(hex) {
190
+ var h = hex.startsWith('0x') ? hex.slice(2) : hex
191
+ var bytes = new Uint8Array(h.length / 2)
192
+ for (var i = 0; i < bytes.length; i++)
193
+ bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16)
194
+ return bytes
195
+ }
196
+
197
+ function bytesToHex(bytes) {
198
+ var hex = '0x'
199
+ for (var i = 0; i < bytes.length; i++)
200
+ hex += bytes[i].toString(16).padStart(2, '0')
201
+ return hex
202
+ }
203
+
204
+ function bigIntToBytes32(value, out, offset) {
205
+ var v = value
206
+ for (var i = 31; i >= 0; i--) {
207
+ out[offset + i] = Number(v & 0xFFn)
208
+ v >>= 8n
209
+ }
210
+ }
211
+
212
+ function mineLoop(data, wasm, mem, postMessage) {
213
+ var addressBytes = hexToBytes(data.address)
214
+ var chunkSize = data.chunkSize
215
+ var count = data.count
216
+ var workerCount = data.workerCount
217
+ var workerIndex = data.workerIndex
218
+ var startBigInt = BigInt(data.start)
219
+
220
+ mem.set(addressBytes, dataOffset)
221
+
222
+ for (
223
+ var chunkIdx = workerIndex;
224
+ chunkIdx * chunkSize < count;
225
+ chunkIdx += workerCount
226
+ ) {
227
+ var chunkStart = chunkIdx * chunkSize
228
+ var limit = Math.min(chunkSize, count - chunkStart)
229
+
230
+ bigIntToBytes32(startBigInt + BigInt(chunkStart), mem, dataOffset + 20)
231
+
232
+ var found = wasm.mine(limit)
233
+
234
+ if (found) {
235
+ var hashOut = mem.slice(dataOffset + 52, dataOffset + 84)
236
+ var salt = mem.slice(dataOffset + 20, dataOffset + 52)
237
+ postMessage({
238
+ type: 'found',
239
+ result: {
240
+ masterId: bytesToHex(hashOut.subarray(4, 8)),
241
+ registrationHash: bytesToHex(hashOut),
242
+ salt: bytesToHex(salt),
243
+ },
244
+ })
245
+ return
246
+ }
247
+
248
+ postMessage({ type: 'progress', attempts: limit })
249
+ }
250
+
251
+ postMessage({ type: 'done' })
252
+ }
253
+ `
254
+ }
package/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = '0.14.18'
2
+ export const version = '0.14.19'