@ethproofs/airbender-wasm-stark-verifier 0.1.0 → 0.1.1

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 CHANGED
@@ -1,41 +1,90 @@
1
- # ethproofs-verifier
1
+ # Airbender Wasm STARK Verifier
2
2
 
3
+ WebAssembly bindings for the Airbender verifier.
3
4
 
4
- First - download the airbender proof from ethproofs.
5
+ ## Overview
5
6
 
6
- Run:
7
+ This module builds the `verify` function from `sp1-verifier` into WebAssembly, enabling STARK proof verification to run directly in both web browsers and Node.js environments.
7
8
 
9
+ ## Usage
10
+
11
+ ### Installation
12
+
13
+ ```bash
14
+ npm install @ethproofs/airbender-wasm-stark-verifier
8
15
  ```
9
- RUST_MIN_STACK=267108864 cargo run --release -- --input-file ~/Downloads/matter-labs_f9c5e994-96fc-45c0-98fe-835a53313a62_705856.bin
16
+
17
+ ### React Integration
18
+
19
+ ```typescript
20
+ import init, {
21
+ main,
22
+ verify_stark,
23
+ } from '@ethproofs/airbender-wasm-stark-verifier';
24
+
25
+ await init(); // Initialize WASM (if needed)
26
+ main(); // Initialize panic hook
27
+
28
+ // Verify a proof
29
+ const isValid = verify_stark(proofBytes, vkBytes);
10
30
  ```
11
31
 
12
- You'll get the output like this:
32
+ ### Node.js Usage
33
+
34
+ ```javascript
35
+ const {
36
+ main,
37
+ verify_stark,
38
+ } = require('@ethproofs/airbender-wasm-stark-verifier');
39
+
40
+ // The Node.js version initializes automatically
13
41
 
42
+ main(); // Initialize panic hook
43
+ const result = verify_stark(proofBytes, vkBytes);
14
44
  ```
15
- End params (recursion verification key): [592082644, 914832686, 2098567393, 2326800689, 2139187838, 4177631951, 1218871476, 1805766682]
16
- Basic program (verification key): [2515378349, 4234595854, 3925512183, 4162864624, 1989541961, 1232249954, 1448623067, 1605092683]
17
- Public input (per block): [2820680802, 124999842, 2275559499, 200691927, 3104886037, 3143080570, 941459835, 587801584]
45
+
46
+ ## Testing
47
+
48
+ ### Installation
49
+
50
+ ```bash
51
+ npm install
18
52
  ```
19
53
 
20
- The first 2 things are verification keys (for recursion and for the 'basic' program).
21
- In theory they should be always 'constant' (and you should build the program + recursion program and check that they match).
54
+ ### Prerequisites
22
55
 
23
- The last entry (public input), would differ for each block, and it represents the hash of the commitment to the block (that contains information like new & old state roots etc).
56
+ - [sp1](https://docs.succinct.xyz/docs/sp1/getting-started/install)
57
+ - [wasm-pack](https://github.com/drager/wasm-pack)
24
58
 
59
+ ### Building
25
60
 
26
- ## Additional options
61
+ ```bash
62
+ # Build for all targets
63
+ npm run build:all
64
+ ```
27
65
 
28
- You can pass `--output_layouts_dir` to output the created setup files to a new directory.
66
+ ### Node.js Example
29
67
 
30
- You can also run with `--use-existing-layout` to use pre-created layouts (which would make program run a lot faster).
68
+ ```bash
69
+ npm run test:node
70
+ ```
31
71
 
72
+ This runs the Node.js example that loads proof and verification key files from the filesystem and verifies them.
32
73
 
33
- # Wasm
74
+ ### Browser Example
34
75
 
35
- ```shell
36
- cargo install wasm-bindgen-cli
76
+ ```bash
77
+ npm run test
37
78
  ```
38
79
 
39
- ```shell
40
- RUSTFLAGS='--cfg getrandom_backend="wasm_js"' wasm-pack build --target web --no-opt
41
- ```
80
+ This starts a local HTTP server at `http://localhost:8080` with a browser example that demonstrates:
81
+
82
+ - Loading the WASM module in a browser environment
83
+ - File upload interface for proof and verification key files
84
+ - Interactive STARK proof verification
85
+ - Performance metrics and detailed logging
86
+ - Error handling and user feedback
87
+
88
+ The browser example provides a complete UI for testing the WASM verifier with drag-and-drop file selection and real-time verification results.
89
+
90
+ **Note:** The browser example requires files to be served over HTTP due to WASM CORS restrictions. The included server script handles this automatically.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethproofs/airbender-wasm-stark-verifier",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "WASM wrapper for Airbender STARK verifier",
5
5
  "type": "module",
6
6
  "main": "pkg/ethproofs_verifier_lib.js",
package/pkg/README.md CHANGED
@@ -1,41 +1,90 @@
1
- # ethproofs-verifier
1
+ # Airbender Wasm STARK Verifier
2
2
 
3
+ WebAssembly bindings for the Airbender verifier.
3
4
 
4
- First - download the airbender proof from ethproofs.
5
+ ## Overview
5
6
 
6
- Run:
7
+ This module builds the `verify` function from `sp1-verifier` into WebAssembly, enabling STARK proof verification to run directly in both web browsers and Node.js environments.
7
8
 
9
+ ## Usage
10
+
11
+ ### Installation
12
+
13
+ ```bash
14
+ npm install @ethproofs/airbender-wasm-stark-verifier
8
15
  ```
9
- RUST_MIN_STACK=267108864 cargo run --release -- --input-file ~/Downloads/matter-labs_f9c5e994-96fc-45c0-98fe-835a53313a62_705856.bin
16
+
17
+ ### React Integration
18
+
19
+ ```typescript
20
+ import init, {
21
+ main,
22
+ verify_stark,
23
+ } from '@ethproofs/airbender-wasm-stark-verifier';
24
+
25
+ await init(); // Initialize WASM (if needed)
26
+ main(); // Initialize panic hook
27
+
28
+ // Verify a proof
29
+ const isValid = verify_stark(proofBytes, vkBytes);
10
30
  ```
11
31
 
12
- You'll get the output like this:
32
+ ### Node.js Usage
33
+
34
+ ```javascript
35
+ const {
36
+ main,
37
+ verify_stark,
38
+ } = require('@ethproofs/airbender-wasm-stark-verifier');
39
+
40
+ // The Node.js version initializes automatically
13
41
 
42
+ main(); // Initialize panic hook
43
+ const result = verify_stark(proofBytes, vkBytes);
14
44
  ```
15
- End params (recursion verification key): [592082644, 914832686, 2098567393, 2326800689, 2139187838, 4177631951, 1218871476, 1805766682]
16
- Basic program (verification key): [2515378349, 4234595854, 3925512183, 4162864624, 1989541961, 1232249954, 1448623067, 1605092683]
17
- Public input (per block): [2820680802, 124999842, 2275559499, 200691927, 3104886037, 3143080570, 941459835, 587801584]
45
+
46
+ ## Testing
47
+
48
+ ### Installation
49
+
50
+ ```bash
51
+ npm install
18
52
  ```
19
53
 
20
- The first 2 things are verification keys (for recursion and for the 'basic' program).
21
- In theory they should be always 'constant' (and you should build the program + recursion program and check that they match).
54
+ ### Prerequisites
22
55
 
23
- The last entry (public input), would differ for each block, and it represents the hash of the commitment to the block (that contains information like new & old state roots etc).
56
+ - [sp1](https://docs.succinct.xyz/docs/sp1/getting-started/install)
57
+ - [wasm-pack](https://github.com/drager/wasm-pack)
24
58
 
59
+ ### Building
25
60
 
26
- ## Additional options
61
+ ```bash
62
+ # Build for all targets
63
+ npm run build:all
64
+ ```
27
65
 
28
- You can pass `--output_layouts_dir` to output the created setup files to a new directory.
66
+ ### Node.js Example
29
67
 
30
- You can also run with `--use-existing-layout` to use pre-created layouts (which would make program run a lot faster).
68
+ ```bash
69
+ npm run test:node
70
+ ```
31
71
 
72
+ This runs the Node.js example that loads proof and verification key files from the filesystem and verifies them.
32
73
 
33
- # Wasm
74
+ ### Browser Example
34
75
 
35
- ```shell
36
- cargo install wasm-bindgen-cli
76
+ ```bash
77
+ npm run test
37
78
  ```
38
79
 
39
- ```shell
40
- RUSTFLAGS='--cfg getrandom_backend="wasm_js"' wasm-pack build --target web --no-opt
41
- ```
80
+ This starts a local HTTP server at `http://localhost:8080` with a browser example that demonstrates:
81
+
82
+ - Loading the WASM module in a browser environment
83
+ - File upload interface for proof and verification key files
84
+ - Interactive STARK proof verification
85
+ - Performance metrics and detailed logging
86
+ - Error handling and user feedback
87
+
88
+ The browser example provides a complete UI for testing the WASM verifier with drag-and-drop file selection and real-time verification results.
89
+
90
+ **Note:** The browser example requires files to be served over HTTP due to WASM CORS restrictions. The included server script handles this automatically.
@@ -1,3 +1,4 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
+ export function main(): void;
3
4
  export function verify_stark(data: Uint8Array): Array<any>;
@@ -36,6 +36,71 @@ function getStringFromWasm0(ptr, len) {
36
36
 
37
37
  let WASM_VECTOR_LEN = 0;
38
38
 
39
+ const cachedTextEncoder = new TextEncoder();
40
+
41
+ if (!('encodeInto' in cachedTextEncoder)) {
42
+ cachedTextEncoder.encodeInto = function (arg, view) {
43
+ const buf = cachedTextEncoder.encode(arg);
44
+ view.set(buf);
45
+ return {
46
+ read: arg.length,
47
+ written: buf.length
48
+ };
49
+ }
50
+ }
51
+
52
+ function passStringToWasm0(arg, malloc, realloc) {
53
+
54
+ if (realloc === undefined) {
55
+ const buf = cachedTextEncoder.encode(arg);
56
+ const ptr = malloc(buf.length, 1) >>> 0;
57
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
58
+ WASM_VECTOR_LEN = buf.length;
59
+ return ptr;
60
+ }
61
+
62
+ let len = arg.length;
63
+ let ptr = malloc(len, 1) >>> 0;
64
+
65
+ const mem = getUint8ArrayMemory0();
66
+
67
+ let offset = 0;
68
+
69
+ for (; offset < len; offset++) {
70
+ const code = arg.charCodeAt(offset);
71
+ if (code > 0x7F) break;
72
+ mem[ptr + offset] = code;
73
+ }
74
+
75
+ if (offset !== len) {
76
+ if (offset !== 0) {
77
+ arg = arg.slice(offset);
78
+ }
79
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
80
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
81
+ const ret = cachedTextEncoder.encodeInto(arg, view);
82
+
83
+ offset += ret.written;
84
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
85
+ }
86
+
87
+ WASM_VECTOR_LEN = offset;
88
+ return ptr;
89
+ }
90
+
91
+ let cachedDataViewMemory0 = null;
92
+
93
+ function getDataViewMemory0() {
94
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
95
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
96
+ }
97
+ return cachedDataViewMemory0;
98
+ }
99
+
100
+ export function main() {
101
+ wasm.main();
102
+ }
103
+
39
104
  function passArray8ToWasm0(arg, malloc) {
40
105
  const ptr = malloc(arg.length * 1, 1) >>> 0;
41
106
  getUint8ArrayMemory0().set(arg, ptr / 1);
@@ -57,6 +122,23 @@ export function __wbg___wbindgen_throw_b855445ff6a94295(arg0, arg1) {
57
122
  throw new Error(getStringFromWasm0(arg0, arg1));
58
123
  };
59
124
 
125
+ export function __wbg_error_7534b8e9a36f1ab4(arg0, arg1) {
126
+ let deferred0_0;
127
+ let deferred0_1;
128
+ try {
129
+ deferred0_0 = arg0;
130
+ deferred0_1 = arg1;
131
+ console.error(getStringFromWasm0(arg0, arg1));
132
+ } finally {
133
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
134
+ }
135
+ };
136
+
137
+ export function __wbg_new_8a6f238a6ece86ea() {
138
+ const ret = new Error();
139
+ return ret;
140
+ };
141
+
60
142
  export function __wbg_new_e17d9f43105b08be() {
61
143
  const ret = new Array();
62
144
  return ret;
@@ -67,6 +149,14 @@ export function __wbg_push_df81a39d04db858c(arg0, arg1) {
67
149
  return ret;
68
150
  };
69
151
 
152
+ export function __wbg_stack_0ed75d68575b0f3c(arg0, arg1) {
153
+ const ret = arg1.stack;
154
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
155
+ const len1 = WASM_VECTOR_LEN;
156
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
157
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
158
+ };
159
+
70
160
  export function __wbindgen_cast_2241b6af4c4b2941(arg0, arg1) {
71
161
  // Cast intrinsic for `Ref(String) -> Externref`.
72
162
  const ret = getStringFromWasm0(arg0, arg1);
Binary file
@@ -2,6 +2,9 @@
2
2
  /* eslint-disable */
3
3
  export const memory: WebAssembly.Memory;
4
4
  export const verify_stark: (a: number, b: number) => any;
5
- export const __wbindgen_externrefs: WebAssembly.Table;
5
+ export const main: () => void;
6
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
6
7
  export const __wbindgen_malloc: (a: number, b: number) => number;
8
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
9
+ export const __wbindgen_externrefs: WebAssembly.Table;
7
10
  export const __wbindgen_start: () => void;
@@ -0,0 +1,323 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Airbender WASM STARK Verifier - Browser Example</title>
7
+ <style>
8
+ body {
9
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
10
+ max-width: 800px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ background-color: #1a1a1a;
14
+ color: #e0e0e0;
15
+ line-height: 1.6;
16
+ }
17
+
18
+ .container {
19
+ background-color: #2d2d2d;
20
+ border-radius: 8px;
21
+ padding: 20px;
22
+ margin-bottom: 20px;
23
+ box-shadow: 0 2px 10px rgba(0,0,0,0.3);
24
+ }
25
+
26
+ h1 {
27
+ color: #4CAF50;
28
+ text-align: center;
29
+ margin-bottom: 30px;
30
+ }
31
+
32
+ h2 {
33
+ color: #81C784;
34
+ border-bottom: 2px solid #4CAF50;
35
+ padding-bottom: 5px;
36
+ }
37
+
38
+ .status {
39
+ padding: 10px;
40
+ border-radius: 4px;
41
+ margin: 10px 0;
42
+ font-weight: bold;
43
+ }
44
+
45
+ .status.loading {
46
+ background-color: #FFF3E0;
47
+ color: #FF8F00;
48
+ border: 1px solid #FFB74D;
49
+ }
50
+
51
+ .status.success {
52
+ background-color: #E8F5E8;
53
+ color: #2E7D32;
54
+ border: 1px solid #4CAF50;
55
+ }
56
+
57
+ .status.error {
58
+ background-color: #FFEBEE;
59
+ color: #C62828;
60
+ border: 1px solid #F44336;
61
+ }
62
+
63
+ .file-info {
64
+ background-color: #424242;
65
+ padding: 10px;
66
+ border-radius: 4px;
67
+ margin: 10px 0;
68
+ font-family: monospace;
69
+ }
70
+
71
+ button {
72
+ background-color: #4CAF50;
73
+ color: white;
74
+ padding: 10px 20px;
75
+ border: none;
76
+ border-radius: 4px;
77
+ cursor: pointer;
78
+ font-size: 16px;
79
+ margin: 10px 5px;
80
+ }
81
+
82
+ button:hover {
83
+ background-color: #45a049;
84
+ }
85
+
86
+ button:disabled {
87
+ background-color: #666;
88
+ cursor: not-allowed;
89
+ }
90
+
91
+ .file-input {
92
+ margin: 10px 0;
93
+ }
94
+
95
+ input[type="file"] {
96
+ background-color: #424242;
97
+ color: #e0e0e0;
98
+ padding: 5px;
99
+ border: 1px solid #666;
100
+ border-radius: 4px;
101
+ }
102
+
103
+ .log {
104
+ background-color: #1e1e1e;
105
+ border: 1px solid #444;
106
+ border-radius: 4px;
107
+ padding: 15px;
108
+ margin: 15px 0;
109
+ font-family: monospace;
110
+ font-size: 12px;
111
+ white-space: pre-wrap;
112
+ max-height: 300px;
113
+ overflow-y: auto;
114
+ }
115
+
116
+ .performance {
117
+ background-color: #263238;
118
+ padding: 10px;
119
+ border-radius: 4px;
120
+ margin: 10px 0;
121
+ }
122
+
123
+ .result {
124
+ font-size: 18px;
125
+ font-weight: bold;
126
+ padding: 15px;
127
+ border-radius: 4px;
128
+ margin: 15px 0;
129
+ text-align: center;
130
+ }
131
+
132
+ .result.valid {
133
+ background-color: #1B5E20;
134
+ color: #4CAF50;
135
+ border: 2px solid #4CAF50;
136
+ }
137
+
138
+ .result.invalid {
139
+ background-color: #B71C1C;
140
+ color: #F44336;
141
+ border: 2px solid #F44336;
142
+ }
143
+ </style>
144
+ </head>
145
+ <body>
146
+ <h1>🧪 Airbender WASM STARK Verifier</h1>
147
+
148
+ <div class="container">
149
+ <h2>Browser Integration Example</h2>
150
+ <p>This example demonstrates how to use the Airbender WASM STARK verifier in a web browser environment.</p>
151
+
152
+ <div id="wasmStatus" class="status loading">Loading WASM module...</div>
153
+ </div>
154
+
155
+ <div class="container">
156
+ <h2>File Selection</h2>
157
+ <p>Select the proof file to test verification:</p>
158
+
159
+ <div class="file-input">
160
+ <label for="proofFile"><strong>Proof file (.bin):</strong></label><br>
161
+ <input type="file" id="proofFile" accept=".bin" />
162
+ <div id="proofInfo" class="file-info" style="display: none;"></div>
163
+ </div>
164
+ </div>
165
+
166
+ <div class="container">
167
+ <h2>Verification</h2>
168
+ <button id="verifyBtn" disabled onclick="runVerification()">Run Verification</button>
169
+ <button id="clearLogBtn" onclick="clearLog()">Clear Log</button>
170
+
171
+ <div id="result" class="result" style="display: none;"></div>
172
+ <div id="performance" class="performance" style="display: none;"></div>
173
+ </div>
174
+
175
+ <div class="container">
176
+ <h2>Console Output</h2>
177
+ <div id="log" class="log"></div>
178
+ </div>
179
+
180
+ <script type="module">
181
+ import init, { main, verify_stark } from './pkg-web/airbender_wasm_stark_verifier.js';
182
+
183
+ let wasmModule = null;
184
+ let proofBytes = null;
185
+
186
+ // Log function to display messages in the UI
187
+ function log(message) {
188
+ const logElement = document.getElementById('log');
189
+ const timestamp = new Date().toLocaleTimeString();
190
+ logElement.textContent += `[${timestamp}] ${message}\n`;
191
+ logElement.scrollTop = logElement.scrollHeight;
192
+ console.log(message);
193
+ }
194
+
195
+ function clearLog() {
196
+ document.getElementById('log').textContent = '';
197
+ }
198
+
199
+ function updateStatus(elementId, message, className) {
200
+ const element = document.getElementById(elementId);
201
+ element.textContent = message;
202
+ element.className = `status ${className}`;
203
+ }
204
+
205
+ function updateFileInfo(elementId, file) {
206
+ const element = document.getElementById(elementId);
207
+ element.style.display = 'block';
208
+ element.innerHTML = `
209
+ <strong>File:</strong> ${file.name}<br>
210
+ <strong>Size:</strong> ${file.size.toLocaleString()} bytes<br>
211
+ <strong>Type:</strong> ${file.type || 'binary'}
212
+ `;
213
+ }
214
+
215
+ function checkCanVerify() {
216
+ const canVerify = wasmModule && proofBytes;
217
+ document.getElementById('verifyBtn').disabled = !canVerify;
218
+ return canVerify;
219
+ }
220
+
221
+ // Initialize WASM module
222
+ async function initializeWasm() {
223
+ try {
224
+ log('🚀 Initializing WASM module...');
225
+ wasmModule = await init();
226
+ log('📦 WASM module loaded, initializing panic hook...');
227
+ main(); // Initialize panic hook and other setup
228
+ updateStatus('wasmStatus', '✅ WASM module loaded successfully', 'success');
229
+ log('✅ WASM module initialized successfully');
230
+ checkCanVerify();
231
+ } catch (error) {
232
+ updateStatus('wasmStatus', `❌ Failed to load WASM module: ${error.message}`, 'error');
233
+ log(`❌ Error initializing WASM: ${error.message}`);
234
+ console.error('WASM initialization error:', error);
235
+ }
236
+ }
237
+
238
+ // File reading helper
239
+ function readFileAsArrayBuffer(file) {
240
+ return new Promise((resolve, reject) => {
241
+ const reader = new FileReader();
242
+ reader.onload = (e) => resolve(new Uint8Array(e.target.result));
243
+ reader.onerror = (e) => reject(new Error(`Failed to read file: ${e.target.error}`));
244
+ reader.readAsArrayBuffer(file);
245
+ });
246
+ }
247
+
248
+ // File input handlers
249
+ document.getElementById('proofFile').addEventListener('change', async (e) => {
250
+ const file = e.target.files[0];
251
+ if (file) {
252
+ try {
253
+ log(`📄 Loading proof file: ${file.name}`);
254
+ proofBytes = await readFileAsArrayBuffer(file);
255
+ updateFileInfo('proofInfo', file);
256
+ log(`✅ Proof file loaded: ${proofBytes.length} bytes`);
257
+ checkCanVerify();
258
+ } catch (error) {
259
+ log(`❌ Error loading proof file: ${error.message}`);
260
+ }
261
+ }
262
+ });
263
+
264
+
265
+ // Main verification function
266
+ window.runVerification = async function() {
267
+ if (!checkCanVerify()) {
268
+ log('❌ Cannot run verification: missing WASM module or proof');
269
+ return;
270
+ }
271
+
272
+ const resultElement = document.getElementById('result');
273
+ const performanceElement = document.getElementById('performance');
274
+
275
+ try {
276
+ log('🔍 Starting verification...');
277
+ log(`📊 Proof size: ${proofBytes.length.toLocaleString()} bytes`);
278
+
279
+ const startTime = performance.now();
280
+ const result = verify_stark(proofBytes);
281
+ const endTime = performance.now();
282
+ const duration = endTime - startTime;
283
+
284
+ // Display result
285
+ resultElement.style.display = 'block';
286
+ resultElement.className = `result ${result ? 'valid' : 'invalid'}`;
287
+ resultElement.textContent = result ? '✅ PROOF VALID' : '❌ PROOF INVALID';
288
+
289
+ // Display performance metrics
290
+ performanceElement.style.display = 'block';
291
+ performanceElement.innerHTML = `
292
+ <strong>⏱️ Performance Metrics:</strong><br>
293
+ Verification time: ${duration.toFixed(2)} milliseconds<br>
294
+ Throughput: ${(proofBytes.length / 1024 / (duration / 1000)).toFixed(2)} KB/s
295
+ `;
296
+
297
+ log(`✅ Verification completed: ${result ? 'VALID' : 'INVALID'}`);
298
+ log(`⏱️ Time taken: ${duration.toFixed(2)} milliseconds`);
299
+
300
+ } catch (error) {
301
+ resultElement.style.display = 'block';
302
+ resultElement.className = 'result invalid';
303
+ resultElement.textContent = `❌ VERIFICATION ERROR: ${error.message}`;
304
+
305
+ log(`❌ Verification error: ${error.message}`);
306
+ console.error('Verification error:', error);
307
+ }
308
+ };
309
+
310
+ // Initialize on page load
311
+ initializeWasm();
312
+
313
+ // Add some helpful information
314
+ log('🌐 Airbender WASM STARK Verifier browser example loaded');
315
+ log('📝 Instructions:');
316
+ log(' 1. Wait for WASM module to load');
317
+ log(' 2. Select a proof file (.bin)');
318
+ log(' 3. Click "Run Verification"');
319
+ log('');
320
+ log('💡 Tip: You can use the proof file from the data/ directory');
321
+ </script>
322
+ </body>
323
+ </html>
package/test-serve.mjs ADDED
@@ -0,0 +1,123 @@
1
+ import http from 'http';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const PORT = process.env.PORT || 8080;
10
+
11
+ // MIME types for different file extensions
12
+ const mimeTypes = {
13
+ '.html': 'text/html',
14
+ '.js': 'application/javascript',
15
+ '.wasm': 'application/wasm',
16
+ '.json': 'application/json',
17
+ '.bin': 'application/octet-stream',
18
+ '.css': 'text/css',
19
+ '.ts': 'application/typescript',
20
+ };
21
+
22
+ function getMimeType(filePath) {
23
+ const ext = path.extname(filePath).toLowerCase();
24
+ return mimeTypes[ext] || 'application/octet-stream';
25
+ }
26
+
27
+ function serveFile(res, filePath) {
28
+ const fullPath = path.join(__dirname, filePath);
29
+
30
+ fs.readFile(fullPath, (err, data) => {
31
+ if (err) {
32
+ // Only log file not found for legitimate requests, not for browser probes
33
+ if (
34
+ !filePath.includes('favicon') &&
35
+ !filePath.includes('ws') &&
36
+ !filePath.includes('socket')
37
+ ) {
38
+ console.error(`❌ File not found: ${filePath}`);
39
+ }
40
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
41
+ res.end('File not found');
42
+ return;
43
+ }
44
+
45
+ const mimeType = getMimeType(filePath);
46
+ const headers = {
47
+ 'Content-Type': mimeType,
48
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
49
+ 'Cross-Origin-Opener-Policy': 'same-origin',
50
+ };
51
+
52
+ // Ensure WASM files are served with correct MIME type for streaming
53
+ if (filePath.endsWith('.wasm')) {
54
+ headers['Content-Type'] = 'application/wasm';
55
+ }
56
+
57
+ res.writeHead(200, headers);
58
+ res.end(data);
59
+
60
+ console.log(`📄 Served: ${filePath} (${mimeType})`);
61
+ });
62
+ }
63
+
64
+ const server = http.createServer((req, res) => {
65
+ let url = req.url;
66
+
67
+ // Handle root path
68
+ if (url === '/') {
69
+ url = '/test-browser.html';
70
+ }
71
+
72
+ // Remove query parameters and decode URL
73
+ url = decodeURIComponent(url.split('?')[0]);
74
+
75
+ // Security check - prevent directory traversal
76
+ if (url.includes('..')) {
77
+ res.writeHead(400, { 'Content-Type': 'text/plain' });
78
+ res.end('Bad Request');
79
+ return;
80
+ }
81
+
82
+ // Handle WebSocket upgrade attempts (reject them gracefully)
83
+ if (req.url === '/ws' || req.headers.upgrade === 'websocket') {
84
+ res.writeHead(400, { 'Content-Type': 'text/plain' });
85
+ res.end('WebSocket connections not supported by this server');
86
+ return;
87
+ }
88
+
89
+ // Remove leading slash for path.join
90
+ const filePath = url.startsWith('/') ? url.slice(1) : url;
91
+
92
+ console.log(`🌐 Request: ${req.method} ${req.url} -> ${filePath}`);
93
+
94
+ serveFile(res, filePath);
95
+ });
96
+
97
+ server.listen(PORT, () => {
98
+ console.log('🚀 Airbender WASM STARK Verifier Example Server');
99
+ console.log(`📡 Server running at http://localhost:${PORT}`);
100
+ console.log('');
101
+ console.log('📝 Available endpoints:');
102
+ console.log(
103
+ ` http://localhost:${PORT}/ - Browser example`
104
+ );
105
+ console.log(
106
+ ` http://localhost:${PORT}/pkg/ - WASM package files`
107
+ );
108
+ console.log(` http://localhost:${PORT}/data/ - Proof files`);
109
+ console.log('');
110
+ console.log(
111
+ '💡 Open your browser and navigate to the server URL to test the WASM verifier!'
112
+ );
113
+ console.log('⏹️ Press Ctrl+C to stop the server');
114
+ });
115
+
116
+ // Graceful shutdown
117
+ process.on('SIGINT', () => {
118
+ console.log('\n🛑 Shutting down server...');
119
+ server.close(() => {
120
+ console.log('✅ Server shut down gracefully');
121
+ process.exit(0);
122
+ });
123
+ });