@aztec/bb.js 0.0.1-alpha.7 → 0.0.1-fake-ceab37513c

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 (227) hide show
  1. package/README.md +69 -32
  2. package/package.json +56 -45
  3. package/src/barretenberg/__snapshots__/pedersen.test.ts.snap +156 -0
  4. package/src/barretenberg/__snapshots__/poseidon.test.ts.snap +40 -0
  5. package/src/barretenberg/backend.ts +378 -0
  6. package/src/barretenberg/blake2s.test.ts +70 -0
  7. package/src/{barretenberg_api → barretenberg}/common.test.ts +7 -5
  8. package/src/barretenberg/index.ts +204 -0
  9. package/src/barretenberg/pedersen.test.ts +62 -0
  10. package/src/barretenberg/poseidon.test.ts +39 -0
  11. package/src/barretenberg_api/index.ts +982 -415
  12. package/src/barretenberg_wasm/barretenberg_wasm_base/index.ts +138 -0
  13. package/src/barretenberg_wasm/barretenberg_wasm_main/factory/browser/index.ts +11 -0
  14. package/src/barretenberg_wasm/barretenberg_wasm_main/factory/browser/main.worker.ts +13 -0
  15. package/src/barretenberg_wasm/barretenberg_wasm_main/factory/node/index.ts +21 -0
  16. package/src/barretenberg_wasm/barretenberg_wasm_main/factory/node/main.worker.ts +19 -0
  17. package/src/{barretenberg_binder/heap_allocator_sync.ts → barretenberg_wasm/barretenberg_wasm_main/heap_allocator.ts} +20 -17
  18. package/src/barretenberg_wasm/barretenberg_wasm_main/index.ts +167 -0
  19. package/src/barretenberg_wasm/barretenberg_wasm_thread/factory/browser/index.ts +11 -0
  20. package/src/barretenberg_wasm/barretenberg_wasm_thread/factory/browser/thread.worker.ts +13 -0
  21. package/src/barretenberg_wasm/barretenberg_wasm_thread/factory/node/index.ts +21 -0
  22. package/src/barretenberg_wasm/barretenberg_wasm_thread/factory/node/thread.worker.ts +19 -0
  23. package/src/barretenberg_wasm/barretenberg_wasm_thread/index.ts +47 -0
  24. package/src/barretenberg_wasm/fetch_code/browser/barretenberg-threads.ts +3 -0
  25. package/src/barretenberg_wasm/fetch_code/browser/barretenberg.ts +3 -0
  26. package/src/barretenberg_wasm/fetch_code/browser/index.ts +34 -0
  27. package/src/barretenberg_wasm/fetch_code/index.ts +1 -0
  28. package/src/barretenberg_wasm/fetch_code/node/index.ts +34 -0
  29. package/src/barretenberg_wasm/fetch_code/wasm-module.d.ts +4 -0
  30. package/src/barretenberg_wasm/helpers/browser/index.ts +47 -0
  31. package/src/barretenberg_wasm/helpers/index.ts +1 -0
  32. package/src/barretenberg_wasm/{node → helpers/node}/index.ts +24 -15
  33. package/src/barretenberg_wasm/index.test.ts +45 -0
  34. package/src/barretenberg_wasm/index.ts +22 -1
  35. package/src/benchmark/index.ts +26 -0
  36. package/src/benchmark/timer.ts +45 -0
  37. package/src/bigint-array/index.ts +39 -17
  38. package/src/bindgen/index.ts +2 -2
  39. package/src/bindgen/mappings.ts +3 -2
  40. package/src/bindgen/typescript.ts +50 -25
  41. package/src/cbind/README.md +1 -0
  42. package/src/cbind/generate.ts +89 -0
  43. package/src/cbind/schema_compiler.ts +833 -0
  44. package/src/crs/browser/cached_net_crs.ts +41 -1
  45. package/src/crs/browser/index.ts +1 -1
  46. package/src/crs/index.ts +1 -1
  47. package/src/crs/net_crs.ts +114 -19
  48. package/src/crs/node/index.ts +96 -26
  49. package/src/index.html +1 -1
  50. package/src/index.ts +13 -5
  51. package/src/log/browser/index.ts +35 -0
  52. package/src/log/index.ts +1 -0
  53. package/src/log/node/index.ts +52 -0
  54. package/src/log/types.ts +6 -0
  55. package/src/main.ts +391 -168
  56. package/src/proof/index.ts +94 -0
  57. package/src/random/browser/index.ts +1 -1
  58. package/src/retry/index.ts +50 -0
  59. package/src/serialize/buffer_reader.ts +4 -1
  60. package/src/types/fields.ts +46 -18
  61. package/src/types/point.ts +4 -1
  62. package/dest/async_map/index.d.ts +0 -10
  63. package/dest/async_map/index.d.ts.map +0 -1
  64. package/dest/async_map/index.js +0 -16
  65. package/dest/barretenberg-threads.wasm +0 -0
  66. package/dest/barretenberg.wasm +0 -0
  67. package/dest/barretenberg_api/blake2s.test.d.ts +0 -2
  68. package/dest/barretenberg_api/blake2s.test.d.ts.map +0 -1
  69. package/dest/barretenberg_api/blake2s.test.js +0 -30
  70. package/dest/barretenberg_api/common.test.d.ts +0 -2
  71. package/dest/barretenberg_api/common.test.d.ts.map +0 -1
  72. package/dest/barretenberg_api/common.test.js +0 -18
  73. package/dest/barretenberg_api/index.d.ts +0 -103
  74. package/dest/barretenberg_api/index.d.ts.map +0 -1
  75. package/dest/barretenberg_api/index.js +0 -379
  76. package/dest/barretenberg_api/pedersen.test.d.ts +0 -2
  77. package/dest/barretenberg_api/pedersen.test.d.ts.map +0 -1
  78. package/dest/barretenberg_api/pedersen.test.js +0 -69
  79. package/dest/barretenberg_api/schnorr.test.d.ts +0 -2
  80. package/dest/barretenberg_api/schnorr.test.d.ts.map +0 -1
  81. package/dest/barretenberg_api/schnorr.test.js +0 -113
  82. package/dest/barretenberg_binder/heap_allocator.d.ts +0 -22
  83. package/dest/barretenberg_binder/heap_allocator.d.ts.map +0 -1
  84. package/dest/barretenberg_binder/heap_allocator.js +0 -59
  85. package/dest/barretenberg_binder/heap_allocator_sync.d.ts +0 -22
  86. package/dest/barretenberg_binder/heap_allocator_sync.d.ts.map +0 -1
  87. package/dest/barretenberg_binder/heap_allocator_sync.js +0 -58
  88. package/dest/barretenberg_binder/index.d.ts +0 -32
  89. package/dest/barretenberg_binder/index.d.ts.map +0 -1
  90. package/dest/barretenberg_binder/index.js +0 -73
  91. package/dest/barretenberg_wasm/barretenberg_wasm.d.ts +0 -50
  92. package/dest/barretenberg_wasm/barretenberg_wasm.d.ts.map +0 -1
  93. package/dest/barretenberg_wasm/barretenberg_wasm.js +0 -212
  94. package/dest/barretenberg_wasm/barretenberg_wasm.test.d.ts +0 -2
  95. package/dest/barretenberg_wasm/barretenberg_wasm.test.d.ts.map +0 -1
  96. package/dest/barretenberg_wasm/barretenberg_wasm.test.js +0 -43
  97. package/dest/barretenberg_wasm/browser/index.d.ts +0 -8
  98. package/dest/barretenberg_wasm/browser/index.d.ts.map +0 -1
  99. package/dest/barretenberg_wasm/browser/index.js +0 -26
  100. package/dest/barretenberg_wasm/browser/worker.d.ts +0 -2
  101. package/dest/barretenberg_wasm/browser/worker.d.ts.map +0 -1
  102. package/dest/barretenberg_wasm/browser/worker.js +0 -11
  103. package/dest/barretenberg_wasm/index.d.ts +0 -2
  104. package/dest/barretenberg_wasm/index.d.ts.map +0 -1
  105. package/dest/barretenberg_wasm/index.js +0 -2
  106. package/dest/barretenberg_wasm/node/index.d.ts +0 -17
  107. package/dest/barretenberg_wasm/node/index.d.ts.map +0 -1
  108. package/dest/barretenberg_wasm/node/index.js +0 -40
  109. package/dest/barretenberg_wasm/node/node_endpoint.d.ts +0 -8
  110. package/dest/barretenberg_wasm/node/node_endpoint.d.ts.map +0 -1
  111. package/dest/barretenberg_wasm/node/node_endpoint.js +0 -28
  112. package/dest/barretenberg_wasm/node/worker.d.ts +0 -2
  113. package/dest/barretenberg_wasm/node/worker.d.ts.map +0 -1
  114. package/dest/barretenberg_wasm/node/worker.js +0 -9
  115. package/dest/barretenberg_wasm.js +0 -2
  116. package/dest/barretenberg_wasm.js.LICENSE.txt +0 -5
  117. package/dest/bigint-array/index.d.ts +0 -3
  118. package/dest/bigint-array/index.d.ts.map +0 -1
  119. package/dest/bigint-array/index.js +0 -21
  120. package/dest/bindgen/function_declaration.d.ts +0 -11
  121. package/dest/bindgen/function_declaration.d.ts.map +0 -1
  122. package/dest/bindgen/function_declaration.js +0 -2
  123. package/dest/bindgen/index.d.ts +0 -2
  124. package/dest/bindgen/index.d.ts.map +0 -1
  125. package/dest/bindgen/index.js +0 -15
  126. package/dest/bindgen/mappings.d.ts +0 -4
  127. package/dest/bindgen/mappings.d.ts.map +0 -1
  128. package/dest/bindgen/mappings.js +0 -63
  129. package/dest/bindgen/rust.d.ts +0 -2
  130. package/dest/bindgen/rust.d.ts.map +0 -1
  131. package/dest/bindgen/rust.js +0 -43
  132. package/dest/bindgen/to_camel_case.d.ts +0 -2
  133. package/dest/bindgen/to_camel_case.d.ts.map +0 -1
  134. package/dest/bindgen/to_camel_case.js +0 -11
  135. package/dest/bindgen/typescript.d.ts +0 -2
  136. package/dest/bindgen/typescript.d.ts.map +0 -1
  137. package/dest/bindgen/typescript.js +0 -80
  138. package/dest/crs/browser/cached_net_crs.d.ts +0 -25
  139. package/dest/crs/browser/cached_net_crs.d.ts.map +0 -1
  140. package/dest/crs/browser/cached_net_crs.js +0 -54
  141. package/dest/crs/browser/index.d.ts +0 -2
  142. package/dest/crs/browser/index.d.ts.map +0 -1
  143. package/dest/crs/browser/index.js +0 -2
  144. package/dest/crs/index.d.ts +0 -2
  145. package/dest/crs/index.d.ts.map +0 -1
  146. package/dest/crs/index.js +0 -2
  147. package/dest/crs/net_crs.d.ts +0 -36
  148. package/dest/crs/net_crs.d.ts.map +0 -1
  149. package/dest/crs/net_crs.js +0 -59
  150. package/dest/crs/node/ignition_files_crs.d.ts +0 -37
  151. package/dest/crs/node/ignition_files_crs.d.ts.map +0 -1
  152. package/dest/crs/node/ignition_files_crs.js +0 -51
  153. package/dest/crs/node/index.d.ts +0 -21
  154. package/dest/crs/node/index.d.ts.map +0 -1
  155. package/dest/crs/node/index.js +0 -54
  156. package/dest/examples/simple.rawtest.d.ts +0 -2
  157. package/dest/examples/simple.rawtest.d.ts.map +0 -1
  158. package/dest/examples/simple.rawtest.js +0 -29
  159. package/dest/examples/simple.test.d.ts +0 -2
  160. package/dest/examples/simple.test.d.ts.map +0 -1
  161. package/dest/examples/simple.test.js +0 -22
  162. package/dest/factory/index.d.ts +0 -21
  163. package/dest/factory/index.d.ts.map +0 -1
  164. package/dest/factory/index.js +0 -34
  165. package/dest/index.d.ts +0 -6
  166. package/dest/index.d.ts.map +0 -1
  167. package/dest/index.html +0 -1
  168. package/dest/index.js +0 -6
  169. package/dest/main.d.ts +0 -10
  170. package/dest/main.d.ts.map +0 -1
  171. package/dest/main.js +0 -275
  172. package/dest/random/browser/index.d.ts +0 -2
  173. package/dest/random/browser/index.d.ts.map +0 -1
  174. package/dest/random/browser/index.js +0 -31
  175. package/dest/random/index.d.ts +0 -2
  176. package/dest/random/index.d.ts.map +0 -1
  177. package/dest/random/index.js +0 -2
  178. package/dest/random/node/index.d.ts +0 -2
  179. package/dest/random/node/index.d.ts.map +0 -1
  180. package/dest/random/node/index.js +0 -5
  181. package/dest/serialize/buffer_reader.d.ts +0 -28
  182. package/dest/serialize/buffer_reader.d.ts.map +0 -1
  183. package/dest/serialize/buffer_reader.js +0 -66
  184. package/dest/serialize/index.d.ts +0 -4
  185. package/dest/serialize/index.d.ts.map +0 -1
  186. package/dest/serialize/index.js +0 -4
  187. package/dest/serialize/output_type.d.ts +0 -11
  188. package/dest/serialize/output_type.d.ts.map +0 -1
  189. package/dest/serialize/output_type.js +0 -44
  190. package/dest/serialize/serialize.d.ts +0 -53
  191. package/dest/serialize/serialize.d.ts.map +0 -1
  192. package/dest/serialize/serialize.js +0 -139
  193. package/dest/simple_test.js +0 -2
  194. package/dest/simple_test.js.LICENSE.txt +0 -14
  195. package/dest/types/fields.d.ts +0 -33
  196. package/dest/types/fields.d.ts.map +0 -1
  197. package/dest/types/fields.js +0 -86
  198. package/dest/types/fixed_size_buffer.d.ts +0 -26
  199. package/dest/types/fixed_size_buffer.d.ts.map +0 -1
  200. package/dest/types/fixed_size_buffer.js +0 -54
  201. package/dest/types/index.d.ts +0 -6
  202. package/dest/types/index.d.ts.map +0 -1
  203. package/dest/types/index.js +0 -6
  204. package/dest/types/point.d.ts +0 -17
  205. package/dest/types/point.d.ts.map +0 -1
  206. package/dest/types/point.js +0 -32
  207. package/dest/types/ptr.d.ts +0 -13
  208. package/dest/types/ptr.d.ts.map +0 -1
  209. package/dest/types/ptr.js +0 -20
  210. package/dest/types/raw_buffer.d.ts +0 -3
  211. package/dest/types/raw_buffer.d.ts.map +0 -1
  212. package/dest/types/raw_buffer.js +0 -5
  213. package/src/barretenberg_api/blake2s.test.ts +0 -39
  214. package/src/barretenberg_api/pedersen.test.ts +0 -84
  215. package/src/barretenberg_api/schnorr.test.ts +0 -169
  216. package/src/barretenberg_binder/heap_allocator.ts +0 -62
  217. package/src/barretenberg_binder/index.ts +0 -76
  218. package/src/barretenberg_wasm/barretenberg_wasm.test.ts +0 -52
  219. package/src/barretenberg_wasm/barretenberg_wasm.ts +0 -246
  220. package/src/barretenberg_wasm/browser/index.ts +0 -32
  221. package/src/barretenberg_wasm/browser/worker.ts +0 -13
  222. package/src/barretenberg_wasm/node/worker.ts +0 -10
  223. package/src/crs/node/ignition_files_crs.ts +0 -60
  224. package/src/examples/simple.rawtest.ts +0 -37
  225. package/src/examples/simple.test.ts +0 -27
  226. package/src/factory/index.ts +0 -36
  227. /package/src/barretenberg_wasm/{node → helpers/node}/node_endpoint.ts +0 -0
@@ -0,0 +1,138 @@
1
+ import { createDebugLogger } from '../../log/index.js';
2
+ import { randomBytes } from '../../random/index.js';
3
+
4
+ /**
5
+ * Base implementation of BarretenbergWasm.
6
+ * Contains code that is common to the "main thread" implementation and the "child thread" implementation.
7
+ */
8
+ export class BarretenbergWasmBase {
9
+ protected memStore: { [key: string]: Uint8Array } = {};
10
+ protected memory!: WebAssembly.Memory;
11
+ protected instance!: WebAssembly.Instance;
12
+ protected logger: (msg: string) => void = createDebugLogger('bb_wasm_base');
13
+
14
+ protected getImportObj(memory: WebAssembly.Memory) {
15
+ /* eslint-disable camelcase */
16
+ const importObj = {
17
+ // We need to implement a part of the wasi api:
18
+ // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md
19
+ // We literally only need to support random_get, everything else is noop implementated in barretenberg.wasm.
20
+ wasi_snapshot_preview1: {
21
+ random_get: (out: any, length: number) => {
22
+ out = out >>> 0;
23
+ const randomData = randomBytes(length);
24
+ const mem = this.getMemory();
25
+ mem.set(randomData, out);
26
+ },
27
+ clock_time_get: (a1: number, a2: number, out: number) => {
28
+ out = out >>> 0;
29
+ const ts = BigInt(new Date().getTime()) * 1000000n;
30
+ const view = new DataView(this.getMemory().buffer);
31
+ view.setBigUint64(out, ts, true);
32
+ },
33
+ proc_exit: () => {
34
+ this.logger('PANIC: proc_exit was called.');
35
+ throw new Error();
36
+ },
37
+ },
38
+
39
+ // These are functions implementations for imports we've defined are needed.
40
+ // The native C++ build defines these in a module called "env". We must implement TypeScript versions here.
41
+ env: {
42
+ /**
43
+ * The 'info' call we use for logging in C++, calls this under the hood.
44
+ * The native code will just print to std:err (to avoid std::cout which is used for IPC).
45
+ * Here we just emit the log line for the client to decide what to do with.
46
+ */
47
+ logstr: (addr: number) => {
48
+ const str = this.stringFromAddress(addr);
49
+ const m = this.getMemory();
50
+ const str2 = `${str} (mem: ${(m.length / (1024 * 1024)).toFixed(2)}MiB)`;
51
+ this.logger(str2);
52
+ },
53
+
54
+ throw_or_abort_impl: (addr: number) => {
55
+ const str = this.stringFromAddress(addr);
56
+ throw new Error(str);
57
+ },
58
+
59
+ get_data: (keyAddr: number, outBufAddr: number) => {
60
+ const key = this.stringFromAddress(keyAddr);
61
+ outBufAddr = outBufAddr >>> 0;
62
+ const data = this.memStore[key];
63
+ if (!data) {
64
+ this.logger(`get_data miss ${key}`);
65
+ return;
66
+ }
67
+ // this.logger(`get_data hit ${key} size: ${data.length} dest: ${outBufAddr}`);
68
+ // this.logger(Buffer.from(data.slice(0, 64)).toString('hex'));
69
+ this.writeMemory(outBufAddr, data);
70
+ },
71
+
72
+ set_data: (keyAddr: number, dataAddr: number, dataLength: number) => {
73
+ const key = this.stringFromAddress(keyAddr);
74
+ dataAddr = dataAddr >>> 0;
75
+ this.memStore[key] = this.getMemorySlice(dataAddr, dataAddr + dataLength);
76
+ // this.logger(`set_data: ${key} length: ${dataLength}`);
77
+ },
78
+
79
+ memory,
80
+ },
81
+ };
82
+ /* eslint-enable camelcase */
83
+
84
+ return importObj;
85
+ }
86
+
87
+ public exports(): any {
88
+ return this.instance.exports;
89
+ }
90
+
91
+ /**
92
+ * When returning values from the WASM, use >>> operator to convert signed representation to unsigned representation.
93
+ */
94
+ public call(name: string, ...args: any) {
95
+ if (!this.exports()[name]) {
96
+ throw new Error(`WASM function ${name} not found.`);
97
+ }
98
+ try {
99
+ return this.exports()[name](...args) >>> 0;
100
+ } catch (err: any) {
101
+ const message = `WASM function ${name} aborted, error: ${err}`;
102
+ this.logger(message);
103
+ this.logger(err.stack);
104
+ throw err;
105
+ }
106
+ }
107
+
108
+ public memSize() {
109
+ return this.getMemory().length;
110
+ }
111
+
112
+ /**
113
+ * Returns a copy of the data, not a view.
114
+ */
115
+ public getMemorySlice(start: number, end: number) {
116
+ return this.getMemory().subarray(start, end).slice();
117
+ }
118
+
119
+ public writeMemory(offset: number, arr: Uint8Array) {
120
+ const mem = this.getMemory();
121
+ mem.set(arr, offset);
122
+ }
123
+
124
+ // PRIVATE METHODS
125
+
126
+ private getMemory() {
127
+ return new Uint8Array(this.memory.buffer);
128
+ }
129
+
130
+ private stringFromAddress(addr: number) {
131
+ addr = addr >>> 0;
132
+ const m = this.getMemory();
133
+ let i = addr;
134
+ for (; m[i] !== 0; ++i);
135
+ const textDecoder = new TextDecoder('ascii');
136
+ return textDecoder.decode(m.slice(addr, i));
137
+ }
138
+ }
@@ -0,0 +1,11 @@
1
+ import { logOptions } from '../../../../log/index.js';
2
+ import { readinessListener } from '../../../helpers/browser/index.js';
3
+
4
+ export async function createMainWorker() {
5
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
+ // @ts-ignore
7
+ const worker = new Worker(new URL('./main.worker.js', import.meta.url), { type: 'module' });
8
+ worker.postMessage({ log: logOptions });
9
+ await new Promise<void>(resolve => readinessListener(worker, resolve));
10
+ return worker;
11
+ }
@@ -0,0 +1,13 @@
1
+ import { expose } from 'comlink';
2
+ import { BarretenbergWasmMain } from '../../index.js';
3
+ import { Ready } from '../../../helpers/browser/index.js';
4
+ import { initLogger } from '../../../../log/browser/index.js';
5
+
6
+ addEventListener('message', e => {
7
+ if (e.data.log) {
8
+ initLogger(e.data.log);
9
+ }
10
+ });
11
+
12
+ expose(new BarretenbergWasmMain());
13
+ postMessage(Ready);
@@ -0,0 +1,21 @@
1
+ import { Worker } from 'worker_threads';
2
+ import { dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { logOptions } from '../../../../log/index.js';
5
+
6
+ function getCurrentDir() {
7
+ if (typeof __dirname !== 'undefined') {
8
+ return __dirname;
9
+ } else {
10
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
11
+ // @ts-ignore
12
+ return dirname(fileURLToPath(import.meta.url));
13
+ }
14
+ }
15
+
16
+ export function createMainWorker() {
17
+ const __dirname = getCurrentDir();
18
+ const worker = new Worker(__dirname + `/main.worker.js`);
19
+ worker.postMessage({ log: logOptions });
20
+ return Promise.resolve(worker);
21
+ }
@@ -0,0 +1,19 @@
1
+ import { parentPort } from 'worker_threads';
2
+ import { expose } from 'comlink';
3
+ import { BarretenbergWasmMain } from '../../index.js';
4
+ import { nodeEndpoint } from '../../../helpers/node/node_endpoint.js';
5
+ import { initLogger } from '../../../../log/node/index.js';
6
+
7
+ if (!parentPort) {
8
+ throw new Error('No parentPort');
9
+ }
10
+
11
+ const endpoint = nodeEndpoint(parentPort);
12
+
13
+ endpoint.addEventListener('message', (e: any) => {
14
+ if (e.data.log) {
15
+ initLogger(e.data.log);
16
+ }
17
+ });
18
+
19
+ expose(new BarretenbergWasmMain(), nodeEndpoint(parentPort));
@@ -1,5 +1,4 @@
1
- import { Bufferable, serializeBufferable, OutputType } from '../serialize/index.js';
2
- import { BarretenbergWasm } from '../barretenberg_wasm/barretenberg_wasm.js';
1
+ import { type BarretenbergWasmMain } from './index.js';
3
2
 
4
3
  /**
5
4
  * Keeps track of heap allocations so they can be easily freed.
@@ -9,33 +8,37 @@ import { BarretenbergWasm } from '../barretenberg_wasm/barretenberg_wasm.js';
9
8
  * Input and output args can use the same scratch space as it's assume all input reads will be performed before any
10
9
  * output writes are performed.
11
10
  */
12
- export class HeapAllocatorSync {
11
+ export class HeapAllocator {
13
12
  private allocs: number[] = [];
14
13
  private inScratchRemaining = 1024;
15
14
  private outScratchRemaining = 1024;
16
15
 
17
- constructor(private wasm: BarretenbergWasm) {}
16
+ constructor(private wasm: BarretenbergWasmMain) {}
18
17
 
19
- copyToMemory(bufferable: Bufferable[]) {
20
- return bufferable.map(serializeBufferable).map(buf => {
21
- if (buf.length <= this.inScratchRemaining) {
22
- const ptr = (this.inScratchRemaining -= buf.length);
23
- this.wasm.writeMemory(ptr, buf);
24
- return ptr;
18
+ getInputs(buffers: (Uint8Array | number)[]) {
19
+ return buffers.map(bufOrNum => {
20
+ if (typeof bufOrNum === 'object') {
21
+ if (bufOrNum.length <= this.inScratchRemaining) {
22
+ const ptr = (this.inScratchRemaining -= bufOrNum.length);
23
+ this.wasm.writeMemory(ptr, bufOrNum);
24
+ return ptr;
25
+ } else {
26
+ const ptr = this.wasm.call('bbmalloc', bufOrNum.length);
27
+ this.wasm.writeMemory(ptr, bufOrNum);
28
+ this.allocs.push(ptr);
29
+ return ptr;
30
+ }
25
31
  } else {
26
- const ptr = this.wasm.call('bbmalloc', buf.length);
27
- this.wasm.writeMemory(ptr, buf);
28
- this.allocs.push(ptr);
29
- return ptr;
32
+ return bufOrNum;
30
33
  }
31
34
  });
32
35
  }
33
36
 
34
- getOutputPtrs(objs: OutputType[]) {
35
- return objs.map(obj => {
37
+ getOutputPtrs(outLens: (number | undefined)[]) {
38
+ return outLens.map(len => {
36
39
  // If the obj is variable length, we need a 4 byte ptr to write the serialized data address to.
37
40
  // WARNING: 4 only works with WASM as it has 32 bit memory.
38
- const size = obj.SIZE_IN_BYTES || 4;
41
+ const size = len || 4;
39
42
 
40
43
  if (size <= this.outScratchRemaining) {
41
44
  return (this.outScratchRemaining -= size);
@@ -0,0 +1,167 @@
1
+ import { type Worker } from 'worker_threads';
2
+ import { Remote } from 'comlink';
3
+ import { getNumCpu, getRemoteBarretenbergWasm, getSharedMemoryAvailable } from '../helpers/index.js';
4
+ import { createThreadWorker } from '../barretenberg_wasm_thread/factory/node/index.js';
5
+ import { type BarretenbergWasmThreadWorker } from '../barretenberg_wasm_thread/index.js';
6
+ import { BarretenbergWasmBase } from '../barretenberg_wasm_base/index.js';
7
+ import { HeapAllocator } from './heap_allocator.js';
8
+ import { createDebugLogger } from '../../log/index.js';
9
+
10
+ /**
11
+ * This is the "main thread" implementation of BarretenbergWasm.
12
+ * It spawns a bunch of "child thread" implementations.
13
+ * In a browser context, this still runs on a worker, as it will block waiting on child threads.
14
+ */
15
+ export class BarretenbergWasmMain extends BarretenbergWasmBase {
16
+ static MAX_THREADS = 32;
17
+ private workers: Worker[] = [];
18
+ private remoteWasms: BarretenbergWasmThreadWorker[] = [];
19
+ private nextWorker = 0;
20
+ private nextThreadId = 1;
21
+
22
+ public getNumThreads() {
23
+ return this.workers.length + 1;
24
+ }
25
+
26
+ /**
27
+ * Init as main thread. Spawn child threads.
28
+ */
29
+ public async init(
30
+ module: WebAssembly.Module,
31
+ threads = Math.min(getNumCpu(), BarretenbergWasmMain.MAX_THREADS),
32
+ logger: (msg: string) => void = createDebugLogger('bb_wasm'),
33
+ initial = 32,
34
+ maximum = this.getDefaultMaximumMemoryPages(),
35
+ ) {
36
+ this.logger = logger;
37
+
38
+ const initialMb = (initial * 2 ** 16) / (1024 * 1024);
39
+ const maxMb = (maximum * 2 ** 16) / (1024 * 1024);
40
+ const shared = getSharedMemoryAvailable();
41
+
42
+ this.logger(
43
+ `Initializing bb wasm: initial memory ${initial} pages ${initialMb}MiB; ` +
44
+ `max memory: ${maximum} pages, ${maxMb}MiB; ` +
45
+ `threads: ${threads}; shared memory: ${shared}`,
46
+ );
47
+
48
+ this.memory = new WebAssembly.Memory({ initial, maximum, shared });
49
+
50
+ const instance = await WebAssembly.instantiate(module, this.getImportObj(this.memory));
51
+
52
+ this.instance = instance;
53
+
54
+ // Init all global/static data.
55
+ this.call('_initialize');
56
+
57
+ // Create worker threads. Create 1 less than requested, as main thread counts as a thread.
58
+ if (threads > 1) {
59
+ this.logger(`Creating ${threads} worker threads`);
60
+ this.workers = await Promise.all(Array.from({ length: threads - 1 }).map(createThreadWorker));
61
+ this.remoteWasms = await Promise.all(this.workers.map(getRemoteBarretenbergWasm<BarretenbergWasmThreadWorker>));
62
+ await Promise.all(this.remoteWasms.map(w => w.initThread(module, this.memory)));
63
+ }
64
+ }
65
+
66
+ private getDefaultMaximumMemoryPages(): number {
67
+ // iOS browser is very aggressive with memory. Check if running in browser and on iOS
68
+ // We at any rate expect the mobile iOS browser to kill us >=1GB, so we don't set a maximum higher than that.
69
+ if (typeof window !== 'undefined' && /iPad|iPhone/.test(navigator.userAgent)) {
70
+ return 2 ** 14;
71
+ }
72
+ return 2 ** 16;
73
+ }
74
+
75
+ /**
76
+ * Called on main thread. Signals child threads to gracefully exit.
77
+ */
78
+ public async destroy() {
79
+ await Promise.all(this.workers.map(w => w.terminate()));
80
+ }
81
+
82
+ protected getImportObj(memory: WebAssembly.Memory) {
83
+ const baseImports = super.getImportObj(memory);
84
+
85
+ /* eslint-disable camelcase */
86
+ return {
87
+ ...baseImports,
88
+ wasi: {
89
+ 'thread-spawn': (arg: number) => {
90
+ arg = arg >>> 0;
91
+ const id = this.nextThreadId++;
92
+ const worker = this.nextWorker++ % this.remoteWasms.length;
93
+ // this.logger(`spawning thread ${id} on worker ${worker} with arg ${arg >>> 0}`);
94
+ this.remoteWasms[worker].call('wasi_thread_start', id, arg).catch(this.logger);
95
+ // this.remoteWasms[worker].postMessage({ msg: 'thread', data: { id, arg } });
96
+ return id;
97
+ },
98
+ },
99
+ env: {
100
+ ...baseImports.env,
101
+ env_hardware_concurrency: () => {
102
+ // If there are no workers (we're already running as a worker, or the main thread requested no workers)
103
+ // then we return 1, which should cause any algos using threading to just not create a thread.
104
+ return this.remoteWasms.length + 1;
105
+ },
106
+ },
107
+ };
108
+ /* eslint-enable camelcase */
109
+ }
110
+
111
+ callWasmExport(funcName: string, inArgs: (Uint8Array | number)[], outLens: (number | undefined)[]) {
112
+ const alloc = new HeapAllocator(this);
113
+ const inPtrs = alloc.getInputs(inArgs);
114
+ const outPtrs = alloc.getOutputPtrs(outLens);
115
+ this.call(funcName, ...inPtrs, ...outPtrs);
116
+ const outArgs = this.getOutputArgs(outLens, outPtrs, alloc);
117
+ alloc.freeAll();
118
+ return outArgs;
119
+ }
120
+
121
+ private getOutputArgs(outLens: (number | undefined)[], outPtrs: number[], alloc: HeapAllocator) {
122
+ return outLens.map((len, i) => {
123
+ if (len) {
124
+ return this.getMemorySlice(outPtrs[i], outPtrs[i] + len);
125
+ }
126
+ const slice = this.getMemorySlice(outPtrs[i], outPtrs[i] + 4);
127
+ const ptr = new DataView(slice.buffer, slice.byteOffset, slice.byteLength).getUint32(0, true);
128
+
129
+ // Add our heap buffer to the dealloc list.
130
+ alloc.addOutputPtr(ptr);
131
+
132
+ // The length will be found in the first 4 bytes of the buffer, big endian. See to_heap_buffer.
133
+ const lslice = this.getMemorySlice(ptr, ptr + 4);
134
+ const length = new DataView(lslice.buffer, lslice.byteOffset, lslice.byteLength).getUint32(0, false);
135
+
136
+ return this.getMemorySlice(ptr + 4, ptr + 4 + length);
137
+ });
138
+ }
139
+
140
+ cbindCall(cbind: string, inputBuffer: Uint8Array): any {
141
+ const outputSizePtr = this.call('bbmalloc', 4);
142
+ const outputMsgpackPtr = this.call('bbmalloc', 4);
143
+
144
+ const inputPtr = this.call('bbmalloc', inputBuffer.length);
145
+ this.writeMemory(inputPtr, inputBuffer);
146
+ this.call(cbind, inputPtr, inputBuffer.length, outputMsgpackPtr, outputSizePtr);
147
+
148
+ const readPtr32 = (ptr32: number) => {
149
+ const dataView = new DataView(this.getMemorySlice(ptr32, ptr32 + 4).buffer);
150
+ return dataView.getUint32(0, true);
151
+ };
152
+
153
+ const encodedResult = this.getMemorySlice(
154
+ readPtr32(outputMsgpackPtr),
155
+ readPtr32(outputMsgpackPtr) + readPtr32(outputSizePtr),
156
+ );
157
+ this.call('bbfree', inputPtr);
158
+ this.call('bbfree', outputSizePtr);
159
+ this.call('bbfree', outputMsgpackPtr);
160
+ return encodedResult;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * The comlink type that asyncifies the BarretenbergWasmMain api.
166
+ */
167
+ export type BarretenbergWasmMainWorker = Remote<BarretenbergWasmMain>;
@@ -0,0 +1,11 @@
1
+ import { logOptions } from '../../../../log/index.js';
2
+ import { readinessListener } from '../../../helpers/browser/index.js';
3
+
4
+ export async function createThreadWorker() {
5
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
+ // @ts-ignore
7
+ const worker = new Worker(new URL('./thread.worker.js', import.meta.url), { type: 'module' });
8
+ worker.postMessage({ log: logOptions });
9
+ await new Promise<void>(resolve => readinessListener(worker, resolve));
10
+ return worker;
11
+ }
@@ -0,0 +1,13 @@
1
+ import { expose } from 'comlink';
2
+ import { BarretenbergWasmThread } from '../../index.js';
3
+ import { Ready } from '../../../helpers/browser/index.js';
4
+ import { initLogger } from '../../../../log/browser/index.js';
5
+
6
+ addEventListener('message', e => {
7
+ if (e.data.log) {
8
+ initLogger(e.data.log);
9
+ }
10
+ });
11
+
12
+ expose(new BarretenbergWasmThread());
13
+ postMessage(Ready);
@@ -0,0 +1,21 @@
1
+ import { Worker } from 'worker_threads';
2
+ import { dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { logOptions } from '../../../../log/index.js';
5
+
6
+ function getCurrentDir() {
7
+ if (typeof __dirname !== 'undefined') {
8
+ return __dirname;
9
+ } else {
10
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
11
+ // @ts-ignore
12
+ return dirname(fileURLToPath(import.meta.url));
13
+ }
14
+ }
15
+
16
+ export function createThreadWorker() {
17
+ const __dirname = getCurrentDir();
18
+ const worker = new Worker(__dirname + `/thread.worker.js`);
19
+ worker.postMessage({ log: logOptions });
20
+ return Promise.resolve(worker);
21
+ }
@@ -0,0 +1,19 @@
1
+ import { parentPort } from 'worker_threads';
2
+ import { expose } from 'comlink';
3
+ import { BarretenbergWasmThread } from '../../index.js';
4
+ import { nodeEndpoint } from '../../../helpers/node/node_endpoint.js';
5
+ import { initLogger } from '../../../../log/node/index.js';
6
+
7
+ if (!parentPort) {
8
+ throw new Error('No parentPort');
9
+ }
10
+
11
+ const endpoint = nodeEndpoint(parentPort);
12
+
13
+ endpoint.addEventListener('message', (e: any) => {
14
+ if (e.data.log) {
15
+ initLogger(e.data.log);
16
+ }
17
+ });
18
+
19
+ expose(new BarretenbergWasmThread(), endpoint);
@@ -0,0 +1,47 @@
1
+ import { Remote } from 'comlink';
2
+ import { killSelf, threadLogger } from '../helpers/index.js';
3
+ import { BarretenbergWasmBase } from '../barretenberg_wasm_base/index.js';
4
+
5
+ export class BarretenbergWasmThread extends BarretenbergWasmBase {
6
+ /**
7
+ * Init as worker thread.
8
+ */
9
+ public async initThread(module: WebAssembly.Module, memory: WebAssembly.Memory) {
10
+ this.logger = threadLogger() || this.logger;
11
+ this.memory = memory;
12
+ this.instance = await WebAssembly.instantiate(module, this.getImportObj(this.memory));
13
+ }
14
+
15
+ public destroy() {
16
+ killSelf();
17
+ }
18
+
19
+ protected getImportObj(memory: WebAssembly.Memory) {
20
+ const baseImports = super.getImportObj(memory);
21
+
22
+ /* eslint-disable camelcase */
23
+ return {
24
+ ...baseImports,
25
+ wasi: {
26
+ 'thread-spawn': () => {
27
+ this.logger('PANIC: threads cannot spawn threads!');
28
+ this.logger(new Error().stack!);
29
+ killSelf();
30
+ },
31
+ },
32
+
33
+ // These are functions implementations for imports we've defined are needed.
34
+ // The native C++ build defines these in a module called "env". We must implement TypeScript versions here.
35
+ env: {
36
+ ...baseImports.env,
37
+ env_hardware_concurrency: () => {
38
+ // We return 1, which should cause any algos using threading to just not create a thread.
39
+ return 1;
40
+ },
41
+ },
42
+ };
43
+ /* eslint-enable camelcase */
44
+ }
45
+ }
46
+
47
+ export type BarretenbergWasmThreadWorker = Remote<BarretenbergWasmThread>;
@@ -0,0 +1,3 @@
1
+ import barretenbergThreadsModule from '../../barretenberg-threads.wasm.gz';
2
+
3
+ export default barretenbergThreadsModule;
@@ -0,0 +1,3 @@
1
+ import barretenbergModule from '../../barretenberg.wasm.gz';
2
+
3
+ export default barretenbergModule;
@@ -0,0 +1,34 @@
1
+ import pako from 'pako';
2
+
3
+ // Annoyingly the wasm declares if it's memory is shared or not. So now we need two wasms if we want to be
4
+ // able to fallback on "non shared memory" situations.
5
+ export async function fetchCode(multithreaded: boolean, wasmPath?: string) {
6
+ let url: string;
7
+ if (wasmPath) {
8
+ const suffix = multithreaded ? '-threads' : '';
9
+ const filePath = wasmPath.split('/').slice(0, -1).join('/');
10
+ const fileNameWithExtensions = wasmPath.split('/').pop();
11
+ const [fileName, ...extensions] = fileNameWithExtensions!.split('.');
12
+ url = `${filePath}/${fileName}${suffix}.${extensions.join('.')}`;
13
+ } else {
14
+ url = multithreaded
15
+ ? (await import('./barretenberg-threads.js')).default
16
+ : (await import('./barretenberg.js')).default;
17
+ }
18
+ const res = await fetch(url);
19
+ // Default bb wasm is compressed, but user could point it to a non-compressed version
20
+ const maybeCompressedData = await res.arrayBuffer();
21
+ const buffer = new Uint8Array(maybeCompressedData);
22
+ const isGzip =
23
+ // Check magic number
24
+ buffer[0] === 0x1f &&
25
+ buffer[1] === 0x8b &&
26
+ // Check compression method:
27
+ buffer[2] === 0x08;
28
+ if (isGzip) {
29
+ const decompressedData = pako.ungzip(buffer);
30
+ return decompressedData.buffer as unknown as Uint8Array<ArrayBuffer>;
31
+ } else {
32
+ return buffer;
33
+ }
34
+ }
@@ -0,0 +1 @@
1
+ export * from './node/index.js';
@@ -0,0 +1,34 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import pako from 'pako';
5
+
6
+ function getCurrentDir() {
7
+ if (typeof __dirname !== 'undefined') {
8
+ return __dirname;
9
+ } else {
10
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
11
+ // @ts-ignore
12
+ return dirname(fileURLToPath(import.meta.url));
13
+ }
14
+ }
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
17
+ export async function fetchCode(multithreaded: boolean, wasmPath?: string) {
18
+ const path = wasmPath ?? getCurrentDir() + '/../../barretenberg-threads.wasm.gz';
19
+ // Default bb wasm is compressed, but user could point it to a non-compressed version
20
+ const maybeCompressedData = await readFile(path);
21
+ const buffer = new Uint8Array(maybeCompressedData);
22
+ const isGzip =
23
+ // Check magic number
24
+ buffer[0] === 0x1f &&
25
+ buffer[1] === 0x8b &&
26
+ // Check compression method:
27
+ buffer[2] === 0x08;
28
+ if (isGzip) {
29
+ const decompressedData = pako.ungzip(buffer);
30
+ return decompressedData.buffer as unknown as Uint8Array<ArrayBuffer>;
31
+ } else {
32
+ return buffer;
33
+ }
34
+ }
@@ -0,0 +1,4 @@
1
+ declare module '*.wasm.gz' {
2
+ const content: string;
3
+ export default content;
4
+ }