├── .gitignore
├── README.md
├── package.json
├── public
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
└── zkxzk.png
├── src
├── App.css
├── App.test.tsx
├── App.tsx
├── bls.ts
├── index.css
├── index.tsx
├── logo.svg
├── reportWebVitals.tsx
├── setupTests.tsx
└── vkey.json
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # zkPairing
2 |
3 | This is the frontend for a demo that took place at DevConnect Amsterdam 2022. The demo can be found [here](https://zkpairing.xyz). We allow users to submit their public key, a BLS signature, and a message (represented as a point on the BLS12-381 curve); these inputs are submitted to a zk-SNARK which checks the validity of the signature. If valid, the server returns a proof to the user; if invalid, an error is displayed.
4 |
5 | The implementation of BLS signatures (which required implementation of elliptic curve pairings in Circom) can be found [here](https://github.com/yi-sun/circom-pairing/). The server setup can be found [here](https://github.com/vincenthuang75025/zk-node-server-c/).
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zkxzk",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@chainsafe/lodestar-types": "^0.34.4",
7 | "@noble/bls12-381": "^1.2.0",
8 | "@testing-library/jest-dom": "^5.16.4",
9 | "@testing-library/react": "^13.0.1",
10 | "@testing-library/user-event": "^13.5.0",
11 | "@types/jest": "^27.4.1",
12 | "@types/node": "^17.0.29",
13 | "@types/react": "^18.0.8",
14 | "@types/react-copy-to-clipboard": "^5.0.2",
15 | "@types/react-dom": "^18.0.0",
16 | "create-react-app": "^5.0.1",
17 | "js-file-download": "^0.4.12",
18 | "react": "^18.0.0",
19 | "react-copy-to-clipboard": "^5.1.0",
20 | "react-dom": "^18.0.0",
21 | "react-scripts": "4.0.3",
22 | "tar-pack": "^3.4.1",
23 | "typescript": "^4.6.3",
24 | "web-vitals": "^2.1.4"
25 | },
26 | "scripts": {
27 | "start": "react-scripts start",
28 | "build": "react-scripts build",
29 | "test": "react-scripts test",
30 | "eject": "react-scripts eject"
31 | },
32 | "browser": {
33 | "crypto": false
34 | },
35 | "eslintConfig": {
36 | "extends": [
37 | "react-app",
38 | "react-app/jest"
39 | ]
40 | },
41 | "browserslist": {
42 | "production": [
43 | "chrome >= 67",
44 | "edge >= 79",
45 | "firefox >= 68",
46 | "opera >= 54",
47 | "safari >= 14"
48 | ],
49 | "development": [
50 | "last 1 chrome version",
51 | "last 1 firefox version",
52 | "last 1 safari version"
53 | ]
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | zkPairing
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincenthuang75025/zkxzk/5edc5c2e0c2255c57d3dc4372968089244d24158/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincenthuang75025/zkxzk/5edc5c2e0c2255c57d3dc4372968089244d24158/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/zkxzk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincenthuang75025/zkxzk/5edc5c2e0c2255c57d3dc4372968089244d24158/public/zkxzk.png
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | padding: 0px 0px;
4 | }
5 |
6 | .App-logo {
7 | width: 25%;
8 | pointer-events: none;
9 | }
10 |
11 | @media (prefers-reduced-motion: no-preference) {
12 | .App-logo {
13 | animation: App-logo-spin infinite 20s linear;
14 | }
15 | }
16 | a {
17 | color: #66bce9;
18 | color: var(--link-color, #66bce9);
19 | text-decoration: none;
20 | background-color: transparent;
21 | }
22 |
23 | a:not(.nav-link) {
24 | text-decoration: none !important;
25 | background-repeat: no-repeat;
26 | background-image: linear-gradient(
27 | 180deg,
28 | transparent 65%,
29 | var(--highlight) 0
30 | );
31 | transition: background-size 0.25s ease;
32 | background-size: 0% 100%;
33 | }
34 |
35 | a:hover {
36 | color: var(--link-hover-color);
37 | }
38 |
39 | .container {
40 | width: 100%;
41 | padding-right: 15px;
42 | padding-left: 15px;
43 | margin-right: auto;
44 | margin-left: auto;
45 | text-align: left;
46 | }
47 |
48 | @media (min-width: 640px) {
49 | .container,
50 | .container-sm {
51 | max-width: 620px;
52 | }
53 | }
54 | @media (min-width: 820px) {
55 | .container,
56 | .container-md,
57 | .container-sm {
58 | max-width: 790px;
59 | }
60 | }
61 | @media (min-width: 1140px) {
62 | .container,
63 | .container-lg,
64 | .container-md,
65 | .container-sm {
66 | max-width: 1110px;
67 | }
68 | }
69 | @media (min-width: 1440px) {
70 | .container,
71 | .container-lg,
72 | .container-md,
73 | .container-sm,
74 | .container-xl {
75 | max-width: 1400px;
76 | }
77 | }
78 | .row {
79 | display: flex;
80 | flex-wrap: wrap;
81 | margin-right: -15px;
82 | margin-left: -15px;
83 | }
84 | .col,
85 | .col-1,
86 | .col-10,
87 | .col-11,
88 | .col-12,
89 | .col-2,
90 | .col-3,
91 | .col-4,
92 | .col-5,
93 | .col-6,
94 | .col-7,
95 | .col-8,
96 | .col-9,
97 | .col-auto,
98 | .col-lg,
99 | .col-lg-1,
100 | .col-lg-10,
101 | .col-lg-11,
102 | .col-lg-12,
103 | .col-lg-2,
104 | .col-lg-3,
105 | .col-lg-4,
106 | .col-lg-5,
107 | .col-lg-6,
108 | .col-lg-7,
109 | .col-lg-8,
110 | .col-lg-9,
111 | .col-lg-auto,
112 | .col-md,
113 | .col-md-1,
114 | .col-md-10,
115 | .col-md-11,
116 | .col-md-12,
117 | .col-md-2,
118 | .col-md-3,
119 | .col-md-4,
120 | .col-md-5,
121 | .col-md-6,
122 | .col-md-7,
123 | .col-md-8,
124 | .col-md-9,
125 | .col-md-auto,
126 | .col-sm,
127 | .col-sm-1,
128 | .col-sm-10,
129 | .col-sm-11,
130 | .col-sm-12,
131 | .col-sm-2,
132 | .col-sm-3,
133 | .col-sm-4,
134 | .col-sm-5,
135 | .col-sm-6,
136 | .col-sm-7,
137 | .col-sm-8,
138 | .col-sm-9,
139 | .col-sm-auto,
140 | .col-xl,
141 | .col-xl-1,
142 | .col-xl-10,
143 | .col-xl-11,
144 | .col-xl-12,
145 | .col-xl-2,
146 | .col-xl-3,
147 | .col-xl-4,
148 | .col-xl-5,
149 | .col-xl-6,
150 | .col-xl-7,
151 | .col-xl-8,
152 | .col-xl-9,
153 | .col-xl-auto {
154 | position: relative;
155 | width: 100%;
156 | padding-right: 15px;
157 | padding-left: 15px;
158 | }
159 | .block-card {
160 | border-top-left-radius: 0;
161 | border-top-right-radius: 0;
162 | }
163 | .card {
164 | background-color: var(--bg-color);
165 | border-radius: 8px;
166 | border-top-left-radius: 8px;
167 | border-top-right-radius: 8px;
168 | box-shadow: 0 2px 8px 0 var(--shadow-color);
169 | position: relative;
170 | display: -ms-flexbox;
171 | display: flex;
172 | -ms-flex-direction: column;
173 | flex-direction: column;
174 | min-width: 0;
175 | word-wrap: break-word;
176 | background-color: #232024;
177 | background-color: var(--bg-color, #232024);
178 | background-clip: border-box;
179 | border: 1px solid rgba(255, 255, 255, 0.125);
180 | border-radius: 0.25rem;
181 | }
182 | .card-body {
183 | -ms-flex: 1 1 auto;
184 | flex: 1 1 auto;
185 | min-height: 1px;
186 | padding: 1.25rem;
187 | }
188 |
189 | .mt-2,
190 | .my-2 {
191 | margin-top: 0.5rem !important;
192 | }
193 | .pb-1,
194 | .py-1 {
195 | padding-bottom: 0.25rem !important;
196 | }
197 | .pt-1,
198 | .py-1 {
199 | padding-top: 0.25rem !important;
200 | }
201 | .pl-0,
202 | .px-0 {
203 | padding-left: 0 !important;
204 | }
205 | .pr-0,
206 | .px-0 {
207 | padding-right: 0 !important;
208 | }
209 | .p-3 {
210 | padding: 1rem !important;
211 | }
212 | .ml-0,
213 | .mx-0 {
214 | margin-left: 0 !important;
215 | }
216 | .mr-0,
217 | .mx-0 {
218 | margin-right: 0 !important;
219 | }
220 | .col-md-2 {
221 | -ms-flex: 0 0 16.666667%;
222 | flex: 0 0 16.666667%;
223 | max-width: 16.666667%;
224 | }
225 | .col-md-10 {
226 | flex: 0 0 83.333333%;
227 | max-width: 83.333333%;
228 | display: flex;
229 | flex-direction: column;
230 | }
231 | .col-md-12 {
232 | max-width: 100%;
233 | display: flex;
234 | flex-direction: column;
235 | }
236 | .col-input {
237 | display: flex;
238 | flex-direction: row;
239 | }
240 | .col-button {
241 | display: flex;
242 | }
243 | *,
244 | ::after,
245 | ::before {
246 | box-sizing: border-box;
247 | }
248 |
249 | .border-bottom {
250 | border-bottom: 1px solid #5c4e4e !important;
251 | }
252 | .App-input {
253 | flex: 1;
254 | background-color: var(--bg-color, #232024);
255 | color: var(--body-color, #dee2e6);
256 | font-family: "Roboto Mono", SFMono-Regular, Menlo, Monaco, Consolas,
257 | "Liberation Mono", "Courier New", monospace !important;
258 | font-size: 1rem;
259 | border: 1px solid rgba(255, 255, 255, 0.125);
260 | border-radius: 0.25rem;
261 | }
262 | .App-input:focus {
263 | outline: none;
264 | border-color: var(--border-color);
265 | }
266 |
267 | .App-button {
268 | display: block;
269 | text-align: center;
270 | width: 100%;
271 | font-family: Inter, sans-serif;
272 | font-size: 1rem;
273 | font-weight: 400;
274 | line-height: 1.5;
275 | background-color: var(--bg);
276 | color: var(--body-color);
277 | border-color: transparent;
278 | padding: 14px 28px;
279 | }
280 | .App-button:hover {
281 | background-color: var(--shadow-dark);
282 | color: var(--shadow-color);
283 | }
284 |
285 | .download-contents {
286 | background: #7d8293;
287 | border-radius: 4px;
288 | bottom: 10px;
289 | color: #fff;
290 | cursor: pointer;
291 | font-family: sans-serif;
292 | font-size: 14px;
293 | font-weight: 600;
294 | height: 30px;
295 | padding: 5px;
296 | position: absolute;
297 | right: 25px;
298 | text-align: center;
299 | }
300 |
301 | .copy-to-clipboard {
302 | background: #7d8293;
303 | border: none;
304 | border-radius: 4px;
305 | bottom: 10px;
306 | height: 30px;
307 | position: absolute;
308 | right: 115px;
309 | width: 30px;
310 | }
311 | .copy-to-clipboard button {
312 | background: url('data:image/svg+xml;charset=utf-8,')
313 | 50% no-repeat;
314 | border: none;
315 | height: 25px;
316 | padding-left: 25px;
317 | cursor: pointer;
318 | }
319 | pre {
320 | display: block;
321 | overflow-x: auto;
322 | padding: 0.5em;
323 | background: rgb(51, 51, 51) none repeat scroll 0% 0%;
324 | color: white;
325 | word-wrap: break-word;
326 | border-radius: 4px;
327 | font-family: monospace;
328 | font-size: 12px;
329 | font-weight: 600;
330 | hyphens: auto;
331 | margin: 0;
332 | white-space: pre-wrap;
333 | word-break: break-word;
334 | max-height: 400px;
335 | min-height: 6em;
336 | overflow-y: auto;
337 | }
338 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, screen } from "@testing-library/react";
3 | import App from "./App";
4 |
5 | test("renders learn react link", () => {
6 | render();
7 | const linkElement = screen.getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { PointG1, PointG2 } from "@noble/bls12-381";
2 | import { ssz } from "@chainsafe/lodestar-types";
3 | import React, { useState, useEffect, WheelEvent } from "react";
4 | import "./App.css";
5 | import {
6 | bigint_to_array,
7 | formatHex,
8 | hexToBytes,
9 | utils,
10 | bytesToHex,
11 | } from "./bls";
12 | import { ReactComponent as Logo } from "./logo.svg";
13 | import saveAs from "js-file-download";
14 | import { CopyToClipboard } from "react-copy-to-clipboard";
15 | // @ts-ignore
16 | import vkey from "./vkey.json";
17 |
18 | const hashToField = utils.hashToField;
19 |
20 | const backend_url = "https://api.zkxzk.xyz/";
21 |
22 | const PrettyPrintJson: React.FC<{
23 | data: string;
24 | fileName?: string;
25 | }> = ({ data, fileName }) => {
26 | const downloadText = () => {
27 | saveAs(data, fileName || "response.txt");
28 | };
29 |
30 | // (destructured) data could be a prop for example
31 | return (
32 |
33 |
{fileName}
34 |
35 | Download
36 |
37 |
38 |
39 |
40 |
41 |
42 |
{data}
43 |
44 | );
45 | };
46 |
47 | /* global BigInt */
48 | function App(): JSX.Element {
49 | const [slot, setSlot] = useState("");
50 | const [epoch, setEpoch] = useState("");
51 | const [pubkeyHex, setPubkeyHex] = useState("");
52 | const [blockRoot, setBlockRoot] = useState("");
53 | const [signatureHex, setSignatureHex] = useState("");
54 |
55 | const [signingRoot, setSigningRoot] = useState("");
56 | const [pubkey, setPubkey] = useState({ 0: "", 1: "" });
57 | const [signature, setSignature] = useState({ 0: "", 1: "", 2: "", 3: "" });
58 | const [message, setMessage] = useState({ 0: "", 1: "", 2: "", 3: "" });
59 | const [id, setId] = useState("");
60 | const [inputJson, setInputJson] = useState("");
61 | const [publicJson, setPublicJson] = useState("");
62 | const [proof, setProof] = useState("");
63 | const [status, setStatus] = useState(0);
64 |
65 | /*useEffect(() => {
66 | msg_hash("abc").then(res => console.log(res));
67 | }, []);*/
68 |
69 | const handlePubkeyChange = (
70 | index: number,
71 | event: React.ChangeEvent
72 | ) => {
73 | setPubkey({ ...pubkey, [index]: event.target.value });
74 | };
75 |
76 | const handleSignatureChange = (
77 | index: number,
78 | event: React.ChangeEvent
79 | ) => {
80 | setSignature({ ...signature, [index]: event.target.value });
81 | };
82 |
83 | const handleMessageChange = (
84 | index: number,
85 | event: React.ChangeEvent
86 | ) => {
87 | setMessage({ ...message, [index]: event.target.value });
88 | };
89 |
90 | async function submitSlot(event: any) {
91 | if (slot === "" || isNaN(Number(slot))) {
92 | alert("Please provide a valid slot number.");
93 | return;
94 | }
95 | try {
96 | let slotNum: number = Number(slot);
97 | let blockJson = await fetch(
98 | "https://beaconcha.in/api/v1/block/" + slotNum.toString()
99 | ).then((res) => {
100 | return res.json();
101 | });
102 | setBlockRoot(blockJson["data"]["blockroot"]);
103 | setEpoch(blockJson["data"]["epoch"]);
104 | setSignatureHex(blockJson["data"]["signature"]);
105 | let proposer: number = Number(blockJson["data"]["proposer"]);
106 | let validatorJson = await fetch(
107 | "https://beaconcha.in/api/v1/validator/" + proposer.toString()
108 | ).then((res) => {
109 | return res.json();
110 | });
111 | setPubkeyHex(validatorJson["data"]["pubkey"]);
112 | } catch {
113 | alert("API call to get block failed.");
114 | }
115 | }
116 | async function submitBlock(event: any) {
117 | if (
118 | epoch === "" ||
119 | pubkeyHex === "" ||
120 | blockRoot === "" ||
121 | signatureHex === ""
122 | ) {
123 | alert("Please fill in all fields");
124 | return;
125 | }
126 | try {
127 | let publicKey = PointG1.fromHex(formatHex(pubkeyHex));
128 | publicKey.assertValidity();
129 | let sig: PointG2 = PointG2.fromSignature(formatHex(signatureHex));
130 | sig.assertValidity();
131 | let root: Uint8Array = hexToBytes(blockRoot);
132 |
133 | // infura API call gives:
134 | const genesisValidatorsRoot: Uint8Array = hexToBytes(
135 | "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"
136 | );
137 |
138 | const ForkData = ssz.phase0.ForkData;
139 | let fork_data = ForkData.defaultValue();
140 |
141 | const ALTAIR_FORK_EPOCH: number = 74240;
142 | if (Number(epoch) < ALTAIR_FORK_EPOCH)
143 | fork_data.currentVersion = hexToBytes("0x00000000");
144 | else fork_data.currentVersion = hexToBytes("0x01000000"); // altair
145 |
146 | fork_data.genesisValidatorsRoot = genesisValidatorsRoot;
147 | let fork_data_root = ForkData.hashTreeRoot(fork_data);
148 |
149 | let domain = new Uint8Array(32);
150 | const DOMAIN_BEACON_PROPOSER = Uint8Array.from([0, 0, 0, 0]);
151 | for (let i = 0; i < 4; i++) domain[i] = DOMAIN_BEACON_PROPOSER[i];
152 | for (let i = 0; i < 28; i++) domain[i + 4] = fork_data_root[i];
153 |
154 | const SigningData = ssz.phase0.SigningData;
155 | let signing_data = SigningData.defaultValue();
156 | signing_data.objectRoot = hexToBytes(blockRoot);
157 | signing_data.domain = domain;
158 | let signing_root: Uint8Array = SigningData.hashTreeRoot(signing_data);
159 |
160 | setSigningRoot("0x" + bytesToHex(signing_root));
161 | let u: bigint[][] = await hashToField(signing_root, 2);
162 |
163 | setPubkey({
164 | 0: "0x" + publicKey.toAffine()[0].value.toString(16),
165 | 1: "0x" + publicKey.toAffine()[1].value.toString(16),
166 | });
167 |
168 | setSignature({
169 | 0: "0x" + sig.toAffine()[0].c[0].value.toString(16),
170 | 1: "0x" + sig.toAffine()[0].c[1].value.toString(16),
171 | 2: "0x" + sig.toAffine()[1].c[0].value.toString(16),
172 | 3: "0x" + sig.toAffine()[1].c[1].value.toString(16),
173 | });
174 |
175 | setMessage({
176 | 0: "0x" + u[0][0].toString(16),
177 | 1: "0x" + u[0][1].toString(16),
178 | 2: "0x" + u[1][0].toString(16),
179 | 3: "0x" + u[1][1].toString(16),
180 | });
181 | } catch {
182 | alert("Input values are not valid. Please try again.");
183 | }
184 | }
185 |
186 | const submitInput = (event: any) => {
187 | if (
188 | message[0] === "" ||
189 | message[1] === "" ||
190 | message[2] === "" ||
191 | message[3] === "" ||
192 | pubkey[0] === "" ||
193 | pubkey[1] === "" ||
194 | signature[0] === "" ||
195 | signature[1] === "" ||
196 | signature[2] === "" ||
197 | signature[3] === ""
198 | ) {
199 | alert("Please fill in all fields");
200 | return;
201 | }
202 | // console.log(JSON.stringify({
203 | // pubkey: [bigint_to_array(55, 7, BigInt(pubkey[0])), bigint_to_array(55, 7, BigInt(pubkey[1]))],
204 | // signature: [[bigint_to_array(55, 7, BigInt(signature[0])), bigint_to_array(55, 7, BigInt(signature[1]))],
205 | // [bigint_to_array(55, 7, BigInt(signature[2])), bigint_to_array(55, 7, BigInt(signature[3]))]],
206 | // hash: [[bigint_to_array(55, 7, BigInt(message[0])), bigint_to_array(55, 7, BigInt(message[1]))],
207 | // [bigint_to_array(55, 7, BigInt(message[2])), bigint_to_array(55, 7, BigInt(message[3]))]]
208 | // }));
209 | let pubkeyArray: string[][] = [
210 | bigint_to_array(55, 7, BigInt(pubkey[0])),
211 | bigint_to_array(55, 7, BigInt(pubkey[1])),
212 | ];
213 | let signatureArray: string[][][] = [
214 | [
215 | bigint_to_array(55, 7, BigInt(signature[0])),
216 | bigint_to_array(55, 7, BigInt(signature[1])),
217 | ],
218 | [
219 | bigint_to_array(55, 7, BigInt(signature[2])),
220 | bigint_to_array(55, 7, BigInt(signature[3])),
221 | ],
222 | ];
223 | let hashArray: string[][][] = [
224 | [
225 | bigint_to_array(55, 7, BigInt(message[0])),
226 | bigint_to_array(55, 7, BigInt(message[1])),
227 | ],
228 | [
229 | bigint_to_array(55, 7, BigInt(message[2])),
230 | bigint_to_array(55, 7, BigInt(message[3])),
231 | ],
232 | ];
233 | let inputStr: string = JSON.stringify(
234 | {
235 | pubkey: pubkeyArray,
236 | signature: signatureArray,
237 | hash: hashArray,
238 | },
239 | null,
240 | 2
241 | );
242 | setInputJson(inputStr);
243 |
244 | let publicArray: string[] = [];
245 | publicArray = publicArray.concat(
246 | pubkeyArray.flat(),
247 | signatureArray[0].flat(),
248 | signatureArray[1].flat(),
249 | hashArray[0].flat(),
250 | hashArray[1].flat()
251 | );
252 | setPublicJson(JSON.stringify(publicArray));
253 |
254 | setProof("");
255 | setStatus(0);
256 |
257 | fetch(backend_url + "generate_proof", {
258 | method: "POST",
259 | headers: {
260 | "Content-Type": "application/json",
261 | },
262 | body: inputStr,
263 | })
264 | .then((res) => res.json())
265 | .then((data) => setId(data.id));
266 | };
267 |
268 | const submitHash = (event: any) => {
269 | if (id !== "") {
270 | fetch(backend_url + "result", {
271 | method: "POST",
272 | headers: {
273 | "Content-Type": "application/json",
274 | },
275 | body: '{"id":"' + id + '"}',
276 | })
277 | .then((response) => {
278 | setStatus(response.status);
279 | console.log(response.status);
280 | return response.json();
281 | })
282 | .then((data) => {
283 | setProof(JSON.stringify(data, null, 2));
284 | });
285 | }
286 | };
287 |
288 | return (
289 | <>
290 |
291 |
292 |
zkPairing
293 |
294 |
295 |
296 |
297 |
298 | Enter a slot from the Beacon Chain to autofill block
299 | information from{" "}
300 |
beaconcha.in:
301 |
302 |
303 |
304 |
305 | Slot:
306 |
307 |
308 | {
314 | setSlot(e.currentTarget.value);
315 | }}
316 | />
317 |
318 |
319 |
320 |
321 |
322 |
325 |
326 |
327 |
328 |
329 |
330 | Enter the following information directly from a block:
331 |
332 |
333 |
334 |
335 | Epoch:
336 |
337 |
338 | {
344 | setEpoch(e.currentTarget.value);
345 | }}
346 | />
347 |
348 |
349 |
350 |
351 | Proposer Public Key:
352 |
353 |
354 | {
360 | setPubkeyHex(e.currentTarget.value);
361 | }}
362 | />
363 |
364 |
365 |
366 |
367 | Block Root:
368 |
369 |
370 | {
376 | setBlockRoot(e.currentTarget.value);
377 | }}
378 | />
379 |
380 |
381 |
382 |
383 | Signature:
384 |
385 |
386 |
396 |
397 |
398 |
399 |
400 |
403 |
404 |
405 |
406 | {signingRoot === "" ? (
407 |
408 | ) : (
409 |
410 |
411 | Signing Root:
412 |
413 |
{signingRoot}
414 |
415 | )}
416 |
417 |
418 | Enter the following inputs for BLS signature verification:
419 |
420 |
421 |
422 |
423 | Public Key (G1 Point):
424 |
425 |
447 |
448 |
449 |
450 | Signature (G2 Point):
451 |
452 |
517 |
518 |
519 |
520 | hashToField(msg, 2):
521 |
522 |
587 |
588 |
589 |
590 |
593 |
594 |
595 | {id === "" ? (
596 |
597 | ) : (
598 | <>
599 |
607 |
608 |
609 | Your job ID is {id}. Generating the proof may take a few
610 | minutes...
611 |
612 |
613 |
614 |
615 |
618 |
619 |
620 | >
621 | )}
622 | {status === 0 ? (
623 | ""
624 | ) : status === 200 ? (
625 | proof ===
626 | JSON.stringify(
627 | JSON.parse(
628 | '{"result": "BLS signature verification failed."}'
629 | ),
630 | null,
631 | 2
632 | ) ? (
633 |
634 |
635 | BLS signature verification failed.
636 |
637 |
638 | ) : (
639 |
640 |
Your proof is ready!
641 |
647 |
653 |
656 |
665 | To verify locally, install{" "}
666 |
snarkjs,
667 | download the three files above, and run:
668 |
674 |
675 | snarkjs groth16 verify vkey.json public.json
676 | proof.json
677 |
678 |
679 |
680 |
681 | )
682 | ) : status === 400 ? (
683 |
684 |
Process still running.
685 |
686 | ) : (
687 |
688 |
689 | Unknown error occured. Please check inputs and try again.
690 |
691 |
692 | )}
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 | >
702 | );
703 | }
704 |
705 | export default App;
706 |
--------------------------------------------------------------------------------
/src/bls.ts:
--------------------------------------------------------------------------------
1 | /*! noble-bls12-381 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
2 | // bls12-381 is a construction of two curves:
3 | // 1. Fp: (x, y)
4 | // 2. Fp₂: ((x₁, x₂+i), (y₁, y₂+i)) - (complex numbers)
5 | //
6 | // Bilinear Pairing (ate pairing) is used to combine both elements into a paired one:
7 | // Fp₁₂ = e(Fp, Fp2)
8 | // where Fp₁₂ = 12-degree polynomial
9 | // Pairing is used to verify signatures.
10 | //
11 | // We are using Fp for private keys (shorter) and Fp2 for signatures (longer).
12 | // Some projects may prefer to swap this relation, it is not supported for now.
13 |
14 | import nodeCrypto from "crypto";
15 | // prettier-ignore
16 |
17 | // To verify curve parameters, see pairing-friendly-curves spec:
18 | // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
19 | // Basic math is done over finite fields over p.
20 | // More complicated math is done over polynominal extension fields.
21 | // To simplify calculations in Fp12, we construct extension tower:
22 | // Fp₁₂ = Fp₆² => Fp₂³
23 | // Fp(u) / (u² - β) where β = -1
24 | // Fp₂(v) / (v³ - ξ) where ξ = u + 1
25 | // Fp₆(w) / (w² - γ) where γ = v
26 | export const CURVE = {
27 | // G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
28 | // characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
29 | P: 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn,
30 | // order; z⁴ − z² + 1
31 | r: 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n,
32 | // cofactor; (z - 1)²/3
33 | h: 0x396c8c005555e1568c00aaab0000aaabn,
34 | // generator's coordinates
35 | // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
36 | // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
37 | Gx: 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bbn,
38 | Gy: 0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1n,
39 | b: 4n,
40 |
41 | // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
42 | // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
43 | // G² - 1
44 | // h2q
45 | P2:
46 | 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn *
47 | 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn -
48 | 1n,
49 | // cofactor
50 | h2: 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5n,
51 | G2x: [
52 | 0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8n,
53 | 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7en,
54 | ],
55 | // y =
56 | // 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
57 | // 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
58 | G2y: [
59 | 0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801n,
60 | 0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79ben,
61 | ],
62 | b2: [4n, 4n],
63 | // The BLS parameter x for BLS12-381
64 | x: 0xd201000000010000n,
65 | h2Eff:
66 | 0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551n,
67 | };
68 |
69 | export function mod(a: bigint, b: bigint) {
70 | const res = a % b;
71 | return res >= 0n ? res : b + res;
72 | }
73 |
74 | const SHA256_DIGEST_SIZE = 32;
75 |
76 | // Default hash_to_field options are for hash to G2.
77 | //
78 | // Parameter definitions are in section 5.3 of the spec unless otherwise noted.
79 | // Parameter values come from section 8.8.2 of the spec.
80 | // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
81 | //
82 | // Base field F is GF(p^m)
83 | // p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
84 | // m = 2 (or 1 for G1 see section 8.8.1)
85 | // k = 128
86 | const htfDefaults = {
87 | // DST: a domain separation tag
88 | // defined in section 2.2.5
89 | DST: "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_", // to comply with https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#bls-signatures
90 | // p: the characteristic of F
91 | // where F is a finite field of characteristic p and order q = p^m
92 | p: CURVE.P,
93 | // m: the extension degree of F, m >= 1
94 | // where F is a finite field of characteristic p and order q = p^m
95 | m: 2,
96 | // k: the target security level for the suite in bits
97 | // defined in section 5.1
98 | k: 128,
99 | // option to use a message that has already been processed by
100 | // expand_message_xmd
101 | expand: true,
102 | };
103 |
104 | // Global symbol available in browsers only. Ensure we do not depend on @types/dom
105 | declare const self: Record | undefined;
106 | const crypto: { node?: any; web?: any } = {
107 | node: nodeCrypto,
108 | web: typeof self === "object" && "crypto" in self ? self.crypto : undefined,
109 | };
110 |
111 | export const utils = {
112 | hashToField: hash_to_field,
113 | bytesToHex,
114 | sha256: async (message: Uint8Array): Promise => {
115 | if (crypto.web) {
116 | const buffer = await crypto.web.subtle.digest("SHA-256", message.buffer);
117 | return new Uint8Array(buffer);
118 | } else if (crypto.node) {
119 | return Uint8Array.from(
120 | crypto.node.createHash("sha256").update(message).digest()
121 | );
122 | } else {
123 | throw new Error("The environment doesn't have sha256 function");
124 | }
125 | },
126 | mod,
127 | };
128 |
129 | const hexes = Array.from({ length: 256 }, (v, i) =>
130 | i.toString(16).padStart(2, "0")
131 | );
132 | export function bytesToHex(uint8a: Uint8Array): string {
133 | // pre-caching chars could speed this up 6x.
134 | let hex = "";
135 | for (let i = 0; i < uint8a.length; i++) {
136 | hex += hexes[uint8a[i]];
137 | }
138 | return hex;
139 | }
140 |
141 | export function formatHex(str: string): string {
142 | if (str.startsWith("0x")) {
143 | str = str.slice(2);
144 | }
145 | return str;
146 | }
147 |
148 | export function hexToBytes(hex: string): Uint8Array {
149 | if (typeof hex !== "string") {
150 | throw new TypeError("hexToBytes: expected string, got " + typeof hex);
151 | }
152 | hex = formatHex(hex);
153 | if (hex.length % 2)
154 | throw new Error("hexToBytes: received invalid unpadded hex");
155 | const array = new Uint8Array(hex.length / 2);
156 | for (let i = 0; i < array.length; i++) {
157 | const j = i * 2;
158 | const hexByte = hex.slice(j, j + 2);
159 | if (hexByte.length !== 2) throw new Error("Invalid byte sequence");
160 | const byte = Number.parseInt(hexByte, 16);
161 | if (Number.isNaN(byte) || byte < 0)
162 | throw new Error("Invalid byte sequence");
163 | array[i] = byte;
164 | }
165 | return array;
166 | }
167 |
168 | function ensureBytes(hex: string | Uint8Array): Uint8Array {
169 | // Uint8Array.from() instead of hash.slice() because node.js Buffer
170 | // is instance of Uint8Array, and its slice() creates **mutable** copy
171 | return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
172 | }
173 |
174 | function concatBytes(...arrays: Uint8Array[]): Uint8Array {
175 | if (arrays.length === 1) return arrays[0];
176 | const length = arrays.reduce((a, arr) => a + arr.length, 0);
177 | const result = new Uint8Array(length);
178 | for (let i = 0, pad = 0; i < arrays.length; i++) {
179 | const arr = arrays[i];
180 | result.set(arr, pad);
181 | pad += arr.length;
182 | }
183 | return result;
184 | }
185 |
186 | // UTF8 to ui8a
187 | function stringToBytes(str: string) {
188 | const bytes = new Uint8Array(str.length);
189 | for (let i = 0; i < str.length; i++) {
190 | bytes[i] = str.charCodeAt(i);
191 | }
192 | return bytes;
193 | }
194 |
195 | // Octet Stream to Integer
196 | function os2ip(bytes: Uint8Array): bigint {
197 | let result = 0n;
198 | for (let i = 0; i < bytes.length; i++) {
199 | result = result * 256n;
200 | result += BigInt(bytes[i]);
201 | }
202 | return result;
203 | }
204 |
205 | // Integer to Octet Stream
206 | function i2osp(value: number, length: number): Uint8Array {
207 | if (value < 0 || value >= 1 << (8 * length)) {
208 | throw new Error(`bad I2OSP call: value=${value} length=${length}`);
209 | }
210 | const res = Array.from({ length }).fill(0) as number[];
211 | for (let i = length - 1; i >= 0; i--) {
212 | res[i] = value & 0xff;
213 | value >>>= 8;
214 | }
215 | return new Uint8Array(res);
216 | }
217 |
218 | function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
219 | const arr = new Uint8Array(a.length);
220 | for (let i = 0; i < a.length; i++) {
221 | arr[i] = a[i] ^ b[i];
222 | }
223 | return arr;
224 | }
225 |
226 | // Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
227 | // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1
228 | async function expand_message_xmd(
229 | msg: Uint8Array,
230 | DST: Uint8Array,
231 | lenInBytes: number
232 | ): Promise {
233 | const H = utils.sha256;
234 | const b_in_bytes = SHA256_DIGEST_SIZE;
235 | const r_in_bytes = b_in_bytes * 2;
236 |
237 | const ell = Math.ceil(lenInBytes / b_in_bytes);
238 | if (ell > 255) throw new Error("Invalid xmd length");
239 | const DST_prime = concatBytes(DST, i2osp(DST.length, 1));
240 | const Z_pad = i2osp(0, r_in_bytes);
241 | const l_i_b_str = i2osp(lenInBytes, 2);
242 | const b = new Array(ell);
243 | const b_0 = await H(
244 | concatBytes(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)
245 | );
246 | b[0] = await H(concatBytes(b_0, i2osp(1, 1), DST_prime));
247 | for (let i = 1; i <= ell; i++) {
248 | const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
249 | b[i] = await H(concatBytes(...args));
250 | }
251 | const pseudo_random_bytes = concatBytes(...b);
252 | return pseudo_random_bytes.slice(0, lenInBytes);
253 | }
254 |
255 | // hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
256 | // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
257 | // Inputs:
258 | // msg - a byte string containing the message to hash.
259 | // count - the number of elements of F to output.
260 | // Outputs:
261 | // [u_0, ..., u_(count - 1)], a list of field elements.
262 | async function hash_to_field(
263 | msg: Uint8Array,
264 | count: number,
265 | options = {}
266 | ): Promise {
267 | // if options is provided but incomplete, fill any missing fields with the
268 | // value in hftDefaults (ie hash to G2).
269 | const htfOptions = { ...htfDefaults, ...options };
270 | const log2p = htfOptions.p.toString(2).length;
271 | const L = Math.ceil((log2p + htfOptions.k) / 8); // section 5.1 of ietf draft link above
272 | const len_in_bytes = count * htfOptions.m * L;
273 | const DST = stringToBytes(htfOptions.DST);
274 | let pseudo_random_bytes = msg;
275 | if (htfOptions.expand) {
276 | pseudo_random_bytes = await expand_message_xmd(msg, DST, len_in_bytes);
277 | }
278 | const u = new Array(count);
279 | for (let i = 0; i < count; i++) {
280 | const e = new Array(htfOptions.m);
281 | for (let j = 0; j < htfOptions.m; j++) {
282 | const elm_offset = L * (j + i * htfOptions.m);
283 | const tv = pseudo_random_bytes.slice(elm_offset, elm_offset + L);
284 | e[j] = mod(os2ip(tv), htfOptions.p);
285 | }
286 | u[i] = e;
287 | }
288 | return u;
289 | }
290 |
291 | export function bigint_to_array(n: number, k: number, x: bigint) {
292 | let mod: bigint = 1n;
293 | for (let idx = 0; idx < n; idx++) {
294 | mod = mod * 2n;
295 | }
296 |
297 | let ret: string[] = [];
298 | var x_temp: bigint = x;
299 | for (let idx = 0; idx < k; idx++) {
300 | ret.push((x_temp % mod).toString());
301 | x_temp = x_temp / mod;
302 | }
303 | return ret;
304 | }
305 |
306 | export async function msg_hash(message: string) {
307 | let msg = stringToBytes(message);
308 |
309 | let u = await hash_to_field(msg, 2);
310 | // return u;
311 |
312 | return [
313 | [bigint_to_array(55, 7, u[0][0]), bigint_to_array(55, 7, u[0][1])],
314 | [bigint_to_array(55, 7, u[1][0]), bigint_to_array(55, 7, u[1][1])],
315 | ];
316 | }
317 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Inter, sans-serif;
3 | font-size: 1rem;
4 | font-weight: 400;
5 | line-height: 1.5;
6 | background-color: var(--bg);
7 | color: var(--body-color, #dee2e6);
8 | text-align: left;
9 | }
10 | :root {
11 | --blue: #3498db;
12 | --indigo: #6610f2;
13 | --purple: #693a39;
14 | --pink: #aa2869;
15 | --red: #f3454a;
16 | --orange: #ffaa31;
17 | --yellow: #f8c988;
18 | --green: #7dc382;
19 | --teal: #37f0f0;
20 | --cyan: #7fd8e6;
21 | --white: #000;
22 | --gray: #c4c4ba;
23 | --gray-dark: #e9ecef;
24 | --shadow-light: rgba(151, 152, 155, 0.2);
25 | --shadow-dark: rgba(159, 162, 177, 0.8);
26 | --font-color: #fff;
27 | --body-color: #dee2e6;
28 | --charade: #2f2e42;
29 | --manhattan: #f5b498;
30 | --rhino: #274253;
31 | --terracotta: #dd765e;
32 | --linear-gradient: linear-gradient(
33 | to right top,
34 | #444359,
35 | #403f55,
36 | #3c3b50,
37 | #38374c,
38 | #343348,
39 | #313045,
40 | #2f2e42,
41 | #2c2b3f,
42 | #2a293d,
43 | #27263a,
44 | #252438,
45 | #232236
46 | );
47 | --shadow-only-light: rgba(0, 0, 0, 0);
48 | --navbar-light-color: rgba(255, 255, 255, 0.5);
49 | --navbar-light-hover-color: rgba(255, 255, 255, 0.7);
50 | --navbar-light-active-color: rgba(255, 255, 255, 0.9);
51 | --navbar-light-disabled-color: rgba(255, 255, 255, 0.3);
52 | --primary: #ffaa31;
53 | --secondary: #c4c4ba;
54 | --success: #7dc382;
55 | --info: #7fd8e6;
56 | --warning: #f8c988;
57 | --danger: #f3454a;
58 | --light: #343a40;
59 | --dark: #e7e1d7;
60 | --bg: #1e1c1f;
61 | --bg-color: #232024;
62 | --shadow-color: #1e1c1f;
63 | --bg-color-light: #5c4e4e55;
64 | --bg-color-nav: #413938;
65 | --bg-color-secondary: #24201f;
66 | --card-border-color: rgba(255, 255, 255, 0.125);
67 | --link-color: #66bce9;
68 | --link-hover-color: #166a96;
69 | --input-color: #dee2e6;
70 | --input-border-color: #6c757d;
71 | --border-color: #5c4e4e;
72 | --border-color-transparent: #5c4e4e80;
73 | --mask-fill-color: #1473e631;
74 | --transparent-font-color: #f5f3f380;
75 | --banner-background: #2f2e42;
76 | --banner-text: #f5b498;
77 | --highlight: rgba(248, 184, 139, 0.2);
78 | --breakpoint-xs: 0;
79 | --breakpoint-sm: 640px;
80 | --breakpoint-md: 820px;
81 | --breakpoint-lg: 1140px;
82 | --breakpoint-xl: 1440px;
83 | --font-family-sans-serif: "Inter", sans-serif;
84 | --font-family-monospace: "Roboto Mono", SFMono-Regular, Menlo, Monaco,
85 | Consolas, "Liberation Mono", "Courier New", monospace;
86 | }
87 | html {
88 | font-family: sans-serif;
89 | line-height: 1.15;
90 | -webkit-text-size-adjust: 100%;
91 | }
92 | html {
93 | font-family: "Inter var", sans-serif;
94 | }
95 | html {
96 | font-family: Inter, sans-serif;
97 | }
98 |
99 | code {
100 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
101 | monospace;
102 | }
103 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 | import reportWebVitals from "./reportWebVitals";
6 |
7 | const root = ReactDOM.createRoot(
8 | document.getElementById("root") as HTMLElement
9 | );
10 | root.render(
11 |
12 |
13 |
14 | );
15 |
16 | // If you want to start measuring performance in your app, pass a function
17 | // to log results (for example: reportWebVitals(console.log))
18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
19 | reportWebVitals();
20 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.tsx:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from "web-vitals";
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/setupTests.tsx:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/vkey.json:
--------------------------------------------------------------------------------
1 | {
2 | "protocol": "groth16",
3 | "curve": "bn128",
4 | "nPublic": 70,
5 | "vk_alpha_1": [
6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042",
7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958",
8 | "1"
9 | ],
10 | "vk_beta_2": [
11 | [
12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731",
13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132"
14 | ],
15 | [
16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856",
17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679"
18 | ],
19 | [
20 | "1",
21 | "0"
22 | ]
23 | ],
24 | "vk_gamma_2": [
25 | [
26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781",
27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634"
28 | ],
29 | [
30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930",
31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531"
32 | ],
33 | [
34 | "1",
35 | "0"
36 | ]
37 | ],
38 | "vk_delta_2": [
39 | [
40 | "13475773117118319559631050521113469874166938234925904165816203174972693625499",
41 | "16090366942136770774825704333373724850232506775834331949642911549091801107353"
42 | ],
43 | [
44 | "13797622015267900234318884768313004774596860824241522013266826448618673776861",
45 | "20363940807123573641357982318184877485356707989158019981793555513789177124304"
46 | ],
47 | [
48 | "1",
49 | "0"
50 | ]
51 | ],
52 | "vk_alphabeta_12": [
53 | [
54 | [
55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885",
56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106"
57 | ],
58 | [
59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312",
60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276"
61 | ],
62 | [
63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277",
64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853"
65 | ]
66 | ],
67 | [
68 | [
69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130",
70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465"
71 | ],
72 | [
73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820",
74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268"
75 | ],
76 | [
77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500",
78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475"
79 | ]
80 | ]
81 | ],
82 | "IC": [
83 | [
84 | "2360648947565767028110556106057533094815151995913626177618316325362554481143",
85 | "4781467002270421911737497145899520609149080288614099368535214242821167423646",
86 | "1"
87 | ],
88 | [
89 | "9671719455670276113573746365142746935448407298341102555889019656700244370975",
90 | "12398074409756775884836161023912376093478123146538306518327996768396254814320",
91 | "1"
92 | ],
93 | [
94 | "16771797607314326703408683472762065943170186961306710315161653891429886567015",
95 | "8291833410420333129035529903494965042571858869498319488723889430947056709278",
96 | "1"
97 | ],
98 | [
99 | "311522335048742816468020401389164734375435719665662514715596401365991226727",
100 | "13172196748204107420861085424890465245210999322462335668644024666335620288227",
101 | "1"
102 | ],
103 | [
104 | "11370776836603999080235799457928007066852174326840707341062205644253967298334",
105 | "2427335320535713779214805362487407761447993175189948229042819786037508288064",
106 | "1"
107 | ],
108 | [
109 | "7808976010636750921298543731614250192248965654995336932207869275052266375814",
110 | "11181313044728652814242029288659834284557135376510799840035090863446459181021",
111 | "1"
112 | ],
113 | [
114 | "18606430655040817291625638953001084580400370657182837496815289001840713706594",
115 | "12427548363296913484868285493710148508815564258748113411195621061381632491014",
116 | "1"
117 | ],
118 | [
119 | "18054343835219722973619054402732961110516119854219889832822608474823939391582",
120 | "6610576214480355636990176295164010630910308060787100907166256416828657469123",
121 | "1"
122 | ],
123 | [
124 | "11787323377363609391931142008736488309467702901137451008228306090337819745566",
125 | "11991442300037186298697569899269570621396630933508940871864270820989260751449",
126 | "1"
127 | ],
128 | [
129 | "4060231476139713616088988973122756541549579429829621068665995961764858995628",
130 | "11454217737870451893265934578300537427466655334694789066680905834465438901897",
131 | "1"
132 | ],
133 | [
134 | "6440284956002218049081468869776712767264344391829754932348158431421667227487",
135 | "18696780161045686611270349282148194296797277230825571986722068045978353968759",
136 | "1"
137 | ],
138 | [
139 | "21062763562655645907254908164011390916314134985234527567697151083403886745344",
140 | "3194248188886259080459376969506932583000836510774443222873629722048076352108",
141 | "1"
142 | ],
143 | [
144 | "14190470410976592713216728572016643620368461790839733185411913984072050321800",
145 | "19274721086443662258082250455906351660750586803627296719979891195811455130493",
146 | "1"
147 | ],
148 | [
149 | "7242724915594281140494310323625836605387236711161393542931259808458526391341",
150 | "18654947281460125150537423548426230330719898676865997004634277664116682535914",
151 | "1"
152 | ],
153 | [
154 | "20785324232916327805060376422192930619347467261653677651409746621984562123210",
155 | "20562023969431214787747825738560844870561226056452173190901034404588290185962",
156 | "1"
157 | ],
158 | [
159 | "10788671387445502140204003917824807564359473840540924952340118426496713572343",
160 | "7878023659383110276431163832261294244620184048115645872179959762362329855555",
161 | "1"
162 | ],
163 | [
164 | "20235392398201610070741328499059615515500922557374546396489395561017917151251",
165 | "17039767043588165564361613391278183749735070811735796374786193880681622631155",
166 | "1"
167 | ],
168 | [
169 | "13480615563085914078129837436647908206778616399420796295047656332439155809409",
170 | "13564792780512193406576690062917059602446895614690736617839399955357153951776",
171 | "1"
172 | ],
173 | [
174 | "15861814257856733020474585690526169714052469613292192196515427339584615084674",
175 | "3187515277923724217321733163385702714685134509148135084234134461791929451316",
176 | "1"
177 | ],
178 | [
179 | "14692905787257426414904096581631508893225126162108944052011904166413805473146",
180 | "18574921032482846221332352539415785862742131904474708284441336858652142693228",
181 | "1"
182 | ],
183 | [
184 | "7924753855963698157056508491341016178921862215909694451480772633026340553151",
185 | "12932751850467943885512404304794968706272350518832518084564763957404419739887",
186 | "1"
187 | ],
188 | [
189 | "14843890987748956347471306947844464297181486682124074485069793603884437724874",
190 | "8275568868899695157273295444643948449278235864237609101402578573659209815295",
191 | "1"
192 | ],
193 | [
194 | "17579054925928839460558699731298350760491044544171166989510711643604071432420",
195 | "19237404068113988538965012614761476278386081051844734118870100739427187791306",
196 | "1"
197 | ],
198 | [
199 | "561850596323941031279044612153916669680931514145473844152760923439951952536",
200 | "12652792679056312614723928825873604664150318131589163767082459372535026177227",
201 | "1"
202 | ],
203 | [
204 | "9299082078414181531936552237189300026536964257063908969831189772828786255848",
205 | "16641178479080970561538128348175323484611962937076510564478206213451284498632",
206 | "1"
207 | ],
208 | [
209 | "9511640721760216672469069114456179498768840062125309925554978838104524920871",
210 | "5626599891478621844389498677255245934054465391284967359216976699797035903945",
211 | "1"
212 | ],
213 | [
214 | "15379898300879067008577631192003115949883289866926205402752487383984426002538",
215 | "1246204758572413488477756316058344957876816894399546922206489634421723093038",
216 | "1"
217 | ],
218 | [
219 | "4283423066548643387638255225705619453510797299772434273199978912075420745861",
220 | "5058935884188116848219107751192581372053629447036924513375294569654650067990",
221 | "1"
222 | ],
223 | [
224 | "8392353168859783938388797595064816469095429058918009941345054765100008820559",
225 | "9946729580969371711812239170576472599001637357342572384957636497686109139497",
226 | "1"
227 | ],
228 | [
229 | "302027653568016972451325713992755703416837815799754856664805014657632951587",
230 | "7095846449176311880754503186208841506377771055630324594121131264120182477219",
231 | "1"
232 | ],
233 | [
234 | "17928185295660200683254596529635457472801800910020757787125276451897040355129",
235 | "3658126482248977882682084596892151444359221643994795175343479403956115555267",
236 | "1"
237 | ],
238 | [
239 | "267148547025489580741845331819679404248744288166636579786469941269717978438",
240 | "1678829077775163851039482287331717445307417585812182485488847657210335164800",
241 | "1"
242 | ],
243 | [
244 | "7024051750253148462776077059693081283701555541016516172650186260554149355142",
245 | "12674427998305427806894755949803175778915515618813419246118499686313701480453",
246 | "1"
247 | ],
248 | [
249 | "2177369816399388807863384449829903278342874431645112410059334145004944154700",
250 | "12331985220049992131348323037912912809685026485614340071615210822950358638818",
251 | "1"
252 | ],
253 | [
254 | "13315732943324830699214507559010052122488596093176150404381042265144837474550",
255 | "17355605042146865959149070183687219595080374697081809259673841589735273262592",
256 | "1"
257 | ],
258 | [
259 | "11820475126574382521385990846239200509944074705112649711807909824082658722219",
260 | "12141920913912106000648069499500788791212872361646122689129389325191830395953",
261 | "1"
262 | ],
263 | [
264 | "16619425038844267230531752921225528387601112643250287094844472409833774683420",
265 | "18915613229979596113973524870205495051348655047780698023879189082447420588896",
266 | "1"
267 | ],
268 | [
269 | "18745854266091920048729290488443682665839878087545004995713878821925233154942",
270 | "18549985803788744175926353318464275392497171383243034522915485774000283995352",
271 | "1"
272 | ],
273 | [
274 | "19617574948966645539980025383483311405972166720960471711070581035638424243402",
275 | "11480923825491057551661687380936237603810457038492205604419883978899124407920",
276 | "1"
277 | ],
278 | [
279 | "12469034321272977355282477688043972346425113055239819177000908411530293618486",
280 | "17486104223558831591800672789260067938331009571965468058914534522878428437156",
281 | "1"
282 | ],
283 | [
284 | "15516028552072837544000765313584743391650184157089349945365709143304858280751",
285 | "14888853617511907001321041986730022083501107416263882284423496512125487997426",
286 | "1"
287 | ],
288 | [
289 | "9946639159755467190674813588727805597104570446711023590656060878848515923266",
290 | "9667330246306460702363020028411686154959501794080815838804988221587248830659",
291 | "1"
292 | ],
293 | [
294 | "19983979755957943863746353310502584945886748502910144562747356035444854796545",
295 | "11435669027183562589681627281932846230899873127541940260409182699046469312561",
296 | "1"
297 | ],
298 | [
299 | "16553003977257868805023228238677093841482162866310941212734777208347819900408",
300 | "9376286826645216288030281233198512260112507317648409213870308888770318497231",
301 | "1"
302 | ],
303 | [
304 | "18743672621918466443059068615435821901919224498340293534749172259012104561690",
305 | "10411233834416423718285946230415037288791180319407968939161675018685070075777",
306 | "1"
307 | ],
308 | [
309 | "9812366978919660883177668956764366645471755041313452072957228861611887664565",
310 | "1214233508015575812054252152670068362133704522066621878878621805186126373989",
311 | "1"
312 | ],
313 | [
314 | "6459395480152830174473209631889202414207645485029544563444124522027268974256",
315 | "17336809347791781229782763453754355042453646654954030175691184543494571959212",
316 | "1"
317 | ],
318 | [
319 | "6510293574091151397884821503643490052875464918728113563235321954237222282564",
320 | "1586619163028196275813078340770835962333907212838306679019824525645729901379",
321 | "1"
322 | ],
323 | [
324 | "10436826643972954843634496863230281180792703030114527989546083394827570391701",
325 | "18246932245927545066390175566749768537780164469727481028093957909307535431049",
326 | "1"
327 | ],
328 | [
329 | "2381363268384365207317845128025645329377709115818561171281858826376154318081",
330 | "11008237343010664655949885061263500187356437714911268520719313764261011703927",
331 | "1"
332 | ],
333 | [
334 | "21002265052673489988783619069125827185267443898718446742544978638669063094404",
335 | "13678781979437291698068882010090931986452473523777989437156238056197279840621",
336 | "1"
337 | ],
338 | [
339 | "12280532885079936998526480297521165358102632288365824120342799708647468616688",
340 | "5711634276438585724786183154741942342947554075953477734959843781372404151659",
341 | "1"
342 | ],
343 | [
344 | "9476179608832096244395218621881954965122362125432862359476532897896737536282",
345 | "20052868023193048692435168728300895799260908222113306169678133521796626931157",
346 | "1"
347 | ],
348 | [
349 | "8118563536046950533416942683389619343921205756589992495093187133083247546255",
350 | "9258323076690265281509701929576480709398425536220667653701484351617107545349",
351 | "1"
352 | ],
353 | [
354 | "261691752480658967989718714897106578702858608105515175966831230466780821717",
355 | "20518139631233075717352307358884759410820299322183216456483817361882138359198",
356 | "1"
357 | ],
358 | [
359 | "3018171838398557810875894783104238526915745947624742624391624147938014570659",
360 | "3691950858336991230269347697840289656694990537703508399683501521112454562906",
361 | "1"
362 | ],
363 | [
364 | "1052329910539245846595809234889146386049960865358100678208304566453502221063",
365 | "6083764653025516906924890364503562135011852097272563920254809198218823634329",
366 | "1"
367 | ],
368 | [
369 | "14577515289867864096164579960545945021343791001324796323263487379998616563026",
370 | "18680039221624274362676631394639711923408192425598506057126839287840180438178",
371 | "1"
372 | ],
373 | [
374 | "14590393586061469340835642674753483343922892843943311804514795791994476285355",
375 | "17363409649275579959924057208210101444228569213517655419960929568679958139477",
376 | "1"
377 | ],
378 | [
379 | "14187063720398850244681395408637801943626264049671896002424902131894991224292",
380 | "21692902941870852068606008837944728856761698134203568857647444831173910276850",
381 | "1"
382 | ],
383 | [
384 | "9180689124546806636755322386876716379656446273923627904301663400472595986099",
385 | "19139697675717852948807646677632060166234660344566847227942040150000948141676",
386 | "1"
387 | ],
388 | [
389 | "20811834459189220993676366834504551477574496170048882257376115633212125570009",
390 | "16434140805458305576184742674429222821002463549043744371358211801744161423606",
391 | "1"
392 | ],
393 | [
394 | "1759164465614701572066690199642803720892803606470150925392205583290086498343",
395 | "11861739070094915485384840885838973878876297386243978628986051523710518991162",
396 | "1"
397 | ],
398 | [
399 | "12402911433995433558922034566902176881234827063645550208132230611065456470427",
400 | "10488240184499240849467212179965676711886128707050992441876864161455918996110",
401 | "1"
402 | ],
403 | [
404 | "10180754841527400070877198792828595544502593315596508085341434729762174202037",
405 | "7872144995764934632193420494805355053978038461336509544534572595994120958345",
406 | "1"
407 | ],
408 | [
409 | "15996494937499479348580021593354017483452880311521134682882847655545098766054",
410 | "21064990612402323470256930116925177022795032160041505691367204000212946146582",
411 | "1"
412 | ],
413 | [
414 | "12368883143550260029343658177130789494435311425929739294332231197539584922762",
415 | "3824535871816827974036673202217053042751575640074861672618548749295956350954",
416 | "1"
417 | ],
418 | [
419 | "12549121467962410459078040045885713975181397234436243588406699091421321249306",
420 | "16925842097107451083601011167967096176064560952595757998731705152632839510352",
421 | "1"
422 | ],
423 | [
424 | "13529977390258239553965146997543827525678492229396244964042215307405307575687",
425 | "9103469360131838420818911740359732730829643950815566419594881248236237402437",
426 | "1"
427 | ],
428 | [
429 | "1883431386930066663651409632104495416118739613730094188284641710202680485291",
430 | "10646724733671901935428260365398316953387224045549200639179200140787659960185",
431 | "1"
432 | ],
433 | [
434 | "6350646664883312156826463937662376894854559740793790222116332479049904868380",
435 | "6597726373851950836683258223952538947664514587830067697386494041252619871324",
436 | "1"
437 | ]
438 | ]
439 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react-jsx",
4 | "target": "ES2020",
5 | "module": "esnext",
6 | "sourceMap": true,
7 | "resolveJsonModule": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "strict": true,
11 | "skipLibCheck": true,
12 | "lib": ["dom", "dom.iterable", "esnext"],
13 | "allowJs": true,
14 | "allowSyntheticDefaultImports": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "moduleResolution": "node",
17 | "isolatedModules": true,
18 | "noEmit": true
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------