@ethproofs/venus-wasm-stark-verifier 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -0
- package/package.json +62 -0
- package/pkg/package.json +17 -0
- package/pkg/venus_wasm_stark_verifier.d.ts +6 -0
- package/pkg/venus_wasm_stark_verifier.js +9 -0
- package/pkg/venus_wasm_stark_verifier_bg.js +161 -0
- package/pkg/venus_wasm_stark_verifier_bg.wasm +0 -0
- package/pkg/venus_wasm_stark_verifier_bg.wasm.d.ts +11 -0
- package/test-browser.html +335 -0
- package/test-serve.mjs +117 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Venus Wasm Stark Verifier
|
|
2
|
+
|
|
3
|
+
WebAssembly bindings for the Venus STARK verifier.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This module builds the `verify_stark` function from Venus's `proofman-verifier` into WebAssembly, enabling STARK proof verification to run directly in both web browsers and Node.js environments.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
### Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @ethproofs/venus-wasm-stark-verifier
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### React Integration
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import init, { main, verify_stark } from '@ethproofs/venus-wasm-stark-verifier';
|
|
21
|
+
|
|
22
|
+
await init(); // Initialize WASM (if needed)
|
|
23
|
+
main(); // Initialize panic hook
|
|
24
|
+
|
|
25
|
+
// Verify a proof
|
|
26
|
+
const isValid = verify_stark(proofBytes, vkBytes);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Node.js Usage
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
const { main, verify_stark } = require('@ethproofs/venus-wasm-stark-verifier');
|
|
33
|
+
|
|
34
|
+
// The Node.js version initializes automatically
|
|
35
|
+
|
|
36
|
+
main(); // Initialize panic hook
|
|
37
|
+
const result = verify_stark(proofBytes, vkBytes);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Testing
|
|
41
|
+
|
|
42
|
+
### Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Prerequisites
|
|
49
|
+
|
|
50
|
+
- [Rust](https://www.rust-lang.org/tools/install)
|
|
51
|
+
- [wasm-pack](https://github.com/drager/wasm-pack)
|
|
52
|
+
|
|
53
|
+
### Building
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Build for all targets
|
|
57
|
+
npm run build:all
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Node.js Example
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm run test:node
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This runs the Node.js example that loads proof and verification key files from the filesystem and verifies them.
|
|
67
|
+
|
|
68
|
+
### Browser Example
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm run test
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This starts a local HTTP server at `http://localhost:8080` with a browser example that demonstrates:
|
|
75
|
+
|
|
76
|
+
- Loading the WASM module in a browser environment
|
|
77
|
+
- File upload interface for proof and verification key files
|
|
78
|
+
- Interactive STARK proof verification
|
|
79
|
+
- Performance metrics and detailed logging
|
|
80
|
+
- Error handling and user feedback
|
|
81
|
+
|
|
82
|
+
The browser example provides a complete UI for testing the WASM verifier with drag-and-drop file selection and real-time verification results.
|
|
83
|
+
|
|
84
|
+
**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
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ethproofs/venus-wasm-stark-verifier",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "WASM wrapper for Venus STARK verifier - verify STARK proofs in browsers and Node.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "pkg/venus_wasm_stark_verifier.js",
|
|
7
|
+
"module": "pkg/venus_wasm_stark_verifier.js",
|
|
8
|
+
"types": "pkg/venus_wasm_stark_verifier.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./pkg/venus_wasm_stark_verifier.d.ts",
|
|
12
|
+
"import": "./pkg/venus_wasm_stark_verifier.js",
|
|
13
|
+
"require": "./pkg/venus_wasm_stark_verifier.js"
|
|
14
|
+
},
|
|
15
|
+
"./pkg/*": "./pkg/*"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"pkg/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"test-browser.html",
|
|
21
|
+
"test-serve.mjs"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "wasm-pack build --target bundler --out-dir pkg",
|
|
25
|
+
"build:node": "wasm-pack build --target nodejs --out-dir pkg-node",
|
|
26
|
+
"build:web": "wasm-pack build --target web --out-dir pkg-web",
|
|
27
|
+
"build:all": "npm run build && npm run build:node && npm run build:web",
|
|
28
|
+
"test": "npm run build && node test-serve.mjs",
|
|
29
|
+
"test:node": "npm run build:node && node test-node.mjs"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"wasm",
|
|
33
|
+
"webassembly",
|
|
34
|
+
"stark",
|
|
35
|
+
"verifier",
|
|
36
|
+
"venus",
|
|
37
|
+
"zero-knowledge",
|
|
38
|
+
"zk",
|
|
39
|
+
"proof",
|
|
40
|
+
"blockchain",
|
|
41
|
+
"cryptography"
|
|
42
|
+
],
|
|
43
|
+
"author": "Ethproofs",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/ethproofs/venus-wasm-stark-verifier"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/ethproofs/venus-wasm-stark-verifier#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/ethproofs/venus-wasm-stark-verifier/issues"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=16.0.0"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"wasm-pack": "^0.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/pkg/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "venus-wasm-stark-verifier",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"files": [
|
|
6
|
+
"venus_wasm_stark_verifier_bg.wasm",
|
|
7
|
+
"venus_wasm_stark_verifier.js",
|
|
8
|
+
"venus_wasm_stark_verifier_bg.js",
|
|
9
|
+
"venus_wasm_stark_verifier.d.ts"
|
|
10
|
+
],
|
|
11
|
+
"main": "venus_wasm_stark_verifier.js",
|
|
12
|
+
"types": "venus_wasm_stark_verifier.d.ts",
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./venus_wasm_stark_verifier.js",
|
|
15
|
+
"./snippets/*"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* @ts-self-types="./venus_wasm_stark_verifier.d.ts" */
|
|
2
|
+
|
|
3
|
+
import * as wasm from "./venus_wasm_stark_verifier_bg.wasm";
|
|
4
|
+
import { __wbg_set_wasm } from "./venus_wasm_stark_verifier_bg.js";
|
|
5
|
+
__wbg_set_wasm(wasm);
|
|
6
|
+
wasm.__wbindgen_start();
|
|
7
|
+
export {
|
|
8
|
+
main, verify_stark
|
|
9
|
+
} from "./venus_wasm_stark_verifier_bg.js";
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
export function main() {
|
|
2
|
+
wasm.main();
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Uint8Array} proof_bytes
|
|
7
|
+
* @param {Uint8Array} vk_bytes
|
|
8
|
+
* @returns {boolean}
|
|
9
|
+
*/
|
|
10
|
+
export function verify_stark(proof_bytes, vk_bytes) {
|
|
11
|
+
const ptr0 = passArray8ToWasm0(proof_bytes, wasm.__wbindgen_malloc);
|
|
12
|
+
const len0 = WASM_VECTOR_LEN;
|
|
13
|
+
const ptr1 = passArray8ToWasm0(vk_bytes, wasm.__wbindgen_malloc);
|
|
14
|
+
const len1 = WASM_VECTOR_LEN;
|
|
15
|
+
const ret = wasm.verify_stark(ptr0, len0, ptr1, len1);
|
|
16
|
+
if (ret[2]) {
|
|
17
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
18
|
+
}
|
|
19
|
+
return ret[0] !== 0;
|
|
20
|
+
}
|
|
21
|
+
export function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
|
|
22
|
+
let deferred0_0;
|
|
23
|
+
let deferred0_1;
|
|
24
|
+
try {
|
|
25
|
+
deferred0_0 = arg0;
|
|
26
|
+
deferred0_1 = arg1;
|
|
27
|
+
console.error(getStringFromWasm0(arg0, arg1));
|
|
28
|
+
} finally {
|
|
29
|
+
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function __wbg_new_227d7c05414eb861() {
|
|
33
|
+
const ret = new Error();
|
|
34
|
+
return ret;
|
|
35
|
+
}
|
|
36
|
+
export function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
|
|
37
|
+
const ret = arg1.stack;
|
|
38
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
39
|
+
const len1 = WASM_VECTOR_LEN;
|
|
40
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
41
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
42
|
+
}
|
|
43
|
+
export function __wbindgen_cast_0000000000000001(arg0, arg1) {
|
|
44
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
45
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
46
|
+
return ret;
|
|
47
|
+
}
|
|
48
|
+
export function __wbindgen_init_externref_table() {
|
|
49
|
+
const table = wasm.__wbindgen_externrefs;
|
|
50
|
+
const offset = table.grow(4);
|
|
51
|
+
table.set(0, undefined);
|
|
52
|
+
table.set(offset + 0, undefined);
|
|
53
|
+
table.set(offset + 1, null);
|
|
54
|
+
table.set(offset + 2, true);
|
|
55
|
+
table.set(offset + 3, false);
|
|
56
|
+
}
|
|
57
|
+
let cachedDataViewMemory0 = null;
|
|
58
|
+
function getDataViewMemory0() {
|
|
59
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
60
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
61
|
+
}
|
|
62
|
+
return cachedDataViewMemory0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getStringFromWasm0(ptr, len) {
|
|
66
|
+
ptr = ptr >>> 0;
|
|
67
|
+
return decodeText(ptr, len);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let cachedUint8ArrayMemory0 = null;
|
|
71
|
+
function getUint8ArrayMemory0() {
|
|
72
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
73
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
74
|
+
}
|
|
75
|
+
return cachedUint8ArrayMemory0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function passArray8ToWasm0(arg, malloc) {
|
|
79
|
+
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
|
80
|
+
getUint8ArrayMemory0().set(arg, ptr / 1);
|
|
81
|
+
WASM_VECTOR_LEN = arg.length;
|
|
82
|
+
return ptr;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
86
|
+
if (realloc === undefined) {
|
|
87
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
88
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
89
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
90
|
+
WASM_VECTOR_LEN = buf.length;
|
|
91
|
+
return ptr;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let len = arg.length;
|
|
95
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
96
|
+
|
|
97
|
+
const mem = getUint8ArrayMemory0();
|
|
98
|
+
|
|
99
|
+
let offset = 0;
|
|
100
|
+
|
|
101
|
+
for (; offset < len; offset++) {
|
|
102
|
+
const code = arg.charCodeAt(offset);
|
|
103
|
+
if (code > 0x7F) break;
|
|
104
|
+
mem[ptr + offset] = code;
|
|
105
|
+
}
|
|
106
|
+
if (offset !== len) {
|
|
107
|
+
if (offset !== 0) {
|
|
108
|
+
arg = arg.slice(offset);
|
|
109
|
+
}
|
|
110
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
111
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
112
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
113
|
+
|
|
114
|
+
offset += ret.written;
|
|
115
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
WASM_VECTOR_LEN = offset;
|
|
119
|
+
return ptr;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function takeFromExternrefTable0(idx) {
|
|
123
|
+
const value = wasm.__wbindgen_externrefs.get(idx);
|
|
124
|
+
wasm.__externref_table_dealloc(idx);
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
129
|
+
cachedTextDecoder.decode();
|
|
130
|
+
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
|
131
|
+
let numBytesDecoded = 0;
|
|
132
|
+
function decodeText(ptr, len) {
|
|
133
|
+
numBytesDecoded += len;
|
|
134
|
+
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
|
135
|
+
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
136
|
+
cachedTextDecoder.decode();
|
|
137
|
+
numBytesDecoded = len;
|
|
138
|
+
}
|
|
139
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const cachedTextEncoder = new TextEncoder();
|
|
143
|
+
|
|
144
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
145
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
146
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
147
|
+
view.set(buf);
|
|
148
|
+
return {
|
|
149
|
+
read: arg.length,
|
|
150
|
+
written: buf.length
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let WASM_VECTOR_LEN = 0;
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
let wasm;
|
|
159
|
+
export function __wbg_set_wasm(val) {
|
|
160
|
+
wasm = val;
|
|
161
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const main: () => void;
|
|
5
|
+
export const verify_stark: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
6
|
+
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
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;
|
|
10
|
+
export const __externref_table_dealloc: (a: number) => void;
|
|
11
|
+
export const __wbindgen_start: () => void;
|
|
@@ -0,0 +1,335 @@
|
|
|
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>Venus 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>Venus WASM STARK Verifier</h1>
|
|
147
|
+
|
|
148
|
+
<div class="container">
|
|
149
|
+
<h2>Browser Integration Example</h2>
|
|
150
|
+
<p>This example demonstrates how to use the Venus 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 and verification key files 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
|
+
|
|
165
|
+
<div class="file-input">
|
|
166
|
+
<label for="vkFile"><strong>Verification Key file (.bin):</strong></label><br>
|
|
167
|
+
<input type="file" id="vkFile" accept=".bin" />
|
|
168
|
+
<div id="vkInfo" class="file-info" style="display: none;"></div>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div class="container">
|
|
173
|
+
<h2>Verification</h2>
|
|
174
|
+
<button id="verifyBtn" disabled onclick="runVerification()">Run Verification</button>
|
|
175
|
+
<button id="clearLogBtn" onclick="clearLog()">Clear Log</button>
|
|
176
|
+
|
|
177
|
+
<div id="result" class="result" style="display: none;"></div>
|
|
178
|
+
<div id="performance" class="performance" style="display: none;"></div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div class="container">
|
|
182
|
+
<h2>Console Output</h2>
|
|
183
|
+
<div id="log" class="log"></div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<script type="module">
|
|
187
|
+
import init, { main, verify_stark } from './pkg-web/venus_wasm_stark_verifier.js';
|
|
188
|
+
|
|
189
|
+
let wasmModule = null;
|
|
190
|
+
let proofBytes = null;
|
|
191
|
+
let vkBytes = null;
|
|
192
|
+
|
|
193
|
+
function log(message) {
|
|
194
|
+
const logElement = document.getElementById('log');
|
|
195
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
196
|
+
logElement.textContent += `[${timestamp}] ${message}\n`;
|
|
197
|
+
logElement.scrollTop = logElement.scrollHeight;
|
|
198
|
+
console.log(message);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function clearLog() {
|
|
202
|
+
document.getElementById('log').textContent = '';
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function updateStatus(elementId, message, className) {
|
|
206
|
+
const element = document.getElementById(elementId);
|
|
207
|
+
element.textContent = message;
|
|
208
|
+
element.className = `status ${className}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function updateFileInfo(elementId, file) {
|
|
212
|
+
const element = document.getElementById(elementId);
|
|
213
|
+
element.style.display = 'block';
|
|
214
|
+
element.innerHTML = `
|
|
215
|
+
<strong>File:</strong> ${file.name}<br>
|
|
216
|
+
<strong>Size:</strong> ${file.size.toLocaleString()} bytes<br>
|
|
217
|
+
<strong>Type:</strong> ${file.type || 'binary'}
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function checkCanVerify() {
|
|
222
|
+
const canVerify = wasmModule && proofBytes && vkBytes;
|
|
223
|
+
document.getElementById('verifyBtn').disabled = !canVerify;
|
|
224
|
+
return canVerify;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function initializeWasm() {
|
|
228
|
+
try {
|
|
229
|
+
log('Initializing WASM module...');
|
|
230
|
+
wasmModule = await init();
|
|
231
|
+
log('WASM module loaded, initializing panic hook...');
|
|
232
|
+
main();
|
|
233
|
+
updateStatus('wasmStatus', 'WASM module loaded successfully', 'success');
|
|
234
|
+
log('WASM module initialized successfully');
|
|
235
|
+
checkCanVerify();
|
|
236
|
+
} catch (error) {
|
|
237
|
+
updateStatus('wasmStatus', `Failed to load WASM module: ${error.message}`, 'error');
|
|
238
|
+
log(`Error initializing WASM: ${error.message}`);
|
|
239
|
+
console.error('WASM initialization error:', error);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function readFileAsArrayBuffer(file) {
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
const reader = new FileReader();
|
|
246
|
+
reader.onload = (e) => resolve(new Uint8Array(e.target.result));
|
|
247
|
+
reader.onerror = (e) => reject(new Error(`Failed to read file: ${e.target.error}`));
|
|
248
|
+
reader.readAsArrayBuffer(file);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
document.getElementById('proofFile').addEventListener('change', async (e) => {
|
|
253
|
+
const file = e.target.files[0];
|
|
254
|
+
if (file) {
|
|
255
|
+
try {
|
|
256
|
+
log(`Loading proof file: ${file.name}`);
|
|
257
|
+
proofBytes = await readFileAsArrayBuffer(file);
|
|
258
|
+
updateFileInfo('proofInfo', file);
|
|
259
|
+
log(`Proof file loaded: ${proofBytes.length} bytes`);
|
|
260
|
+
checkCanVerify();
|
|
261
|
+
} catch (error) {
|
|
262
|
+
log(`Error loading proof file: ${error.message}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
document.getElementById('vkFile').addEventListener('change', async (e) => {
|
|
268
|
+
const file = e.target.files[0];
|
|
269
|
+
if (file) {
|
|
270
|
+
try {
|
|
271
|
+
log(`Loading verification key file: ${file.name}`);
|
|
272
|
+
vkBytes = await readFileAsArrayBuffer(file);
|
|
273
|
+
updateFileInfo('vkInfo', file);
|
|
274
|
+
log(`Verification key loaded: ${vkBytes.length} bytes`);
|
|
275
|
+
checkCanVerify();
|
|
276
|
+
} catch (error) {
|
|
277
|
+
log(`Error loading verification key file: ${error.message}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
window.runVerification = async function() {
|
|
283
|
+
if (!checkCanVerify()) {
|
|
284
|
+
log('Cannot run verification: missing WASM module, proof, or verification key');
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const resultElement = document.getElementById('result');
|
|
289
|
+
const performanceElement = document.getElementById('performance');
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
log('Starting verification...');
|
|
293
|
+
log(`Proof size: ${proofBytes.length.toLocaleString()} bytes`);
|
|
294
|
+
log(`VK size: ${vkBytes.length.toLocaleString()} bytes`);
|
|
295
|
+
|
|
296
|
+
const startTime = performance.now();
|
|
297
|
+
const result = verify_stark(proofBytes, vkBytes);
|
|
298
|
+
const endTime = performance.now();
|
|
299
|
+
const duration = endTime - startTime;
|
|
300
|
+
|
|
301
|
+
resultElement.style.display = 'block';
|
|
302
|
+
resultElement.className = `result ${result ? 'valid' : 'invalid'}`;
|
|
303
|
+
resultElement.textContent = result ? 'PROOF VALID' : 'PROOF INVALID';
|
|
304
|
+
|
|
305
|
+
performanceElement.style.display = 'block';
|
|
306
|
+
performanceElement.innerHTML = `
|
|
307
|
+
<strong>Performance Metrics:</strong><br>
|
|
308
|
+
Verification time: ${duration.toFixed(2)} milliseconds<br>
|
|
309
|
+
Throughput: ${((proofBytes.length + vkBytes.length) / 1024 / (duration / 1000)).toFixed(2)} KB/s
|
|
310
|
+
`;
|
|
311
|
+
|
|
312
|
+
log(`Verification completed: ${result ? 'VALID' : 'INVALID'}`);
|
|
313
|
+
log(`Time taken: ${duration.toFixed(2)} milliseconds`);
|
|
314
|
+
|
|
315
|
+
} catch (error) {
|
|
316
|
+
resultElement.style.display = 'block';
|
|
317
|
+
resultElement.className = 'result invalid';
|
|
318
|
+
resultElement.textContent = `VERIFICATION ERROR: ${error.message}`;
|
|
319
|
+
|
|
320
|
+
log(`Verification error: ${error.message}`);
|
|
321
|
+
console.error('Verification error:', error);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
initializeWasm();
|
|
326
|
+
|
|
327
|
+
log('Venus WASM STARK Verifier browser example loaded');
|
|
328
|
+
log('Instructions:');
|
|
329
|
+
log(' 1. Wait for WASM module to load');
|
|
330
|
+
log(' 2. Select a proof file (.bin)');
|
|
331
|
+
log(' 3. Select a verification key file (.bin)');
|
|
332
|
+
log(' 4. Click "Run Verification"');
|
|
333
|
+
</script>
|
|
334
|
+
</body>
|
|
335
|
+
</html>
|
package/test-serve.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
const mimeTypes = {
|
|
12
|
+
'.html': 'text/html',
|
|
13
|
+
'.js': 'application/javascript',
|
|
14
|
+
'.wasm': 'application/wasm',
|
|
15
|
+
'.json': 'application/json',
|
|
16
|
+
'.bin': 'application/octet-stream',
|
|
17
|
+
'.css': 'text/css',
|
|
18
|
+
'.ts': 'application/typescript',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function getMimeType(filePath) {
|
|
22
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
23
|
+
return mimeTypes[ext] || 'application/octet-stream';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function serveFile(res, filePath) {
|
|
27
|
+
const fullPath = path.join(__dirname, filePath);
|
|
28
|
+
|
|
29
|
+
fs.readFile(fullPath, (err, data) => {
|
|
30
|
+
if (err) {
|
|
31
|
+
if (
|
|
32
|
+
!filePath.includes('favicon') &&
|
|
33
|
+
!filePath.includes('ws') &&
|
|
34
|
+
!filePath.includes('socket')
|
|
35
|
+
) {
|
|
36
|
+
console.error(`File not found: ${filePath}`);
|
|
37
|
+
}
|
|
38
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
39
|
+
res.end('File not found');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const mimeType = getMimeType(filePath);
|
|
44
|
+
const headers = {
|
|
45
|
+
'Content-Type': mimeType,
|
|
46
|
+
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
47
|
+
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (filePath.endsWith('.wasm')) {
|
|
51
|
+
headers['Content-Type'] = 'application/wasm';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
res.writeHead(200, headers);
|
|
55
|
+
res.end(data);
|
|
56
|
+
|
|
57
|
+
console.log(`Served: ${filePath} (${mimeType})`);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const server = http.createServer((req, res) => {
|
|
62
|
+
let url = req.url;
|
|
63
|
+
|
|
64
|
+
if (url === '/') {
|
|
65
|
+
url = '/test-browser.html';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
url = decodeURIComponent(url.split('?')[0]);
|
|
69
|
+
|
|
70
|
+
if (url.includes('..')) {
|
|
71
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
72
|
+
res.end('Bad Request');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (req.url === '/ws' || req.headers.upgrade === 'websocket') {
|
|
77
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
78
|
+
res.end('WebSocket connections not supported by this server');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const filePath = url.startsWith('/') ? url.slice(1) : url;
|
|
83
|
+
|
|
84
|
+
console.log(`Request: ${req.method} ${req.url} -> ${filePath}`);
|
|
85
|
+
|
|
86
|
+
serveFile(res, filePath);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
server.listen(PORT, () => {
|
|
90
|
+
console.log('Venus WASM STARK Verifier Example Server');
|
|
91
|
+
console.log(`Server running at http://localhost:${PORT}`);
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log('Available endpoints:');
|
|
94
|
+
console.log(
|
|
95
|
+
` http://localhost:${PORT}/ - Browser example`
|
|
96
|
+
);
|
|
97
|
+
console.log(
|
|
98
|
+
` http://localhost:${PORT}/pkg/ - WASM package files`
|
|
99
|
+
);
|
|
100
|
+
console.log(` http://localhost:${PORT}/proofs/ - Proof files`);
|
|
101
|
+
console.log(
|
|
102
|
+
` http://localhost:${PORT}/vks/ - Verification keys`
|
|
103
|
+
);
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(
|
|
106
|
+
'Open your browser and navigate to the server URL to test the WASM verifier!'
|
|
107
|
+
);
|
|
108
|
+
console.log('Press Ctrl+C to stop the server');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
process.on('SIGINT', () => {
|
|
112
|
+
console.log('\nShutting down server...');
|
|
113
|
+
server.close(() => {
|
|
114
|
+
console.log('Server shut down gracefully');
|
|
115
|
+
process.exit(0);
|
|
116
|
+
});
|
|
117
|
+
});
|