Files
crypt-keeper-extension/demo/index.tsx
0xmad 0093c93d0d chore: dev improvements
- [x] Add eslint and prettier ignore files
- [x] Add types check for precommit hook
- [x] Add types for local demo
2023-02-21 16:37:34 -06:00

287 lines
7.8 KiB
TypeScript

/* eslint-disable no-console */
import React, { useState, useEffect, useCallback } from "react";
import ReactDOM from "react-dom";
import { RLN, genExternalNullifier } from "rlnjs";
import { bigintToHex } from "bigint-conversion";
import { Identity } from "@semaphore-protocol/identity";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import log from "loglevel";
import type { Client } from "@src/contentscripts/injected";
const SERVER_URL = "http://localhost:8090";
const semaphorePath = {
circuitFilePath: `${SERVER_URL}/zkeyFiles/semaphore/semaphore.wasm`,
zkeyFilePath: `${SERVER_URL}/zkeyFiles/semaphore/semaphore.zkey`,
verificationKey: `${SERVER_URL}/zkeyFiles/semaphore/verification_key.json`,
};
const rlnPath = {
circuitFilePath: `${SERVER_URL}/zkeyFiles/rln/rln.wasm`,
zkeyFilePath: `${SERVER_URL}/zkeyFiles/rln/rln.zkey`,
verificationKey: `${SERVER_URL}/zkeyFiles/rln/verification_key.json`,
};
const merkleStorageAddress = `${SERVER_URL}/merkleProof`;
enum MerkleProofType {
STORAGE_ADDRESS,
ARTIFACTS,
}
declare global {
interface Window {
zkpr: {
connect: () => Promise<Client | null>;
};
}
}
const genMockIdentityCommitments = (): string[] => {
const identityCommitments: string[] = [];
for (let i = 0; i < 10; i++) {
const mockIdentity = new Identity();
const idCommitment = bigintToHex(mockIdentity.getCommitment());
identityCommitments.push(idCommitment);
}
return identityCommitments;
};
interface INotConnectedProps {
onClick: () => void;
}
function NotConnected({ onClick }: INotConnectedProps) {
return (
<div>
Please connect to Crypt-Keeper to continue. <button onClick={onClick}>Connect</button>
</div>
);
}
function NoActiveIDCommitment() {
return <div>Please set an active Identity Commitment in the Crypt-Keeper plugin to continue.</div>;
}
function App() {
const [client, setClient] = useState<Client | null>(null);
const [isLocked, setIsLocked] = useState(true);
const [identityCommitment, setIdentityCommitment] = useState("");
const mockIdentityCommitments: string[] = genMockIdentityCommitments();
const genSemaphoreProof = async (proofType: MerkleProofType = MerkleProofType.STORAGE_ADDRESS) => {
const externalNullifier = genExternalNullifier("voting-1");
const signal = "0x111";
let storageAddressOrArtifacts: any = `${merkleStorageAddress}/Semaphore`;
if (proofType === MerkleProofType.ARTIFACTS) {
if (!mockIdentityCommitments.includes(identityCommitment)) {
mockIdentityCommitments.push(identityCommitment);
}
storageAddressOrArtifacts = {
leaves: mockIdentityCommitments,
depth: 20,
leavesPerNode: 2,
};
}
let toastId;
try {
toastId = toast("Generating semaphore proof...", {
type: "info",
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: false,
});
const proof = await client?.semaphoreProof(
externalNullifier,
signal,
semaphorePath.circuitFilePath,
semaphorePath.zkeyFilePath,
storageAddressOrArtifacts,
);
console.log("Semaphore proof generated successfully!", proof);
toast("Semaphore proof generated successfully!", { type: "success" });
} catch (e) {
toast("Error while generating Semaphore proof!", { type: "error" });
console.error(e);
}
toast.dismiss(toastId);
};
const genRLNProof = async (proofType: MerkleProofType = MerkleProofType.STORAGE_ADDRESS) => {
const externalNullifier = genExternalNullifier("voting-1");
const signal = "0x111";
const rlnIdentifier = RLN._genIdentifier();
const rlnIdentifierHex = bigintToHex(rlnIdentifier);
let storageAddressOrArtifacts: any = `${merkleStorageAddress}/RLN`;
if (proofType === MerkleProofType.ARTIFACTS) {
if (!mockIdentityCommitments.includes(identityCommitment)) {
mockIdentityCommitments.push(identityCommitment);
}
storageAddressOrArtifacts = {
leaves: mockIdentityCommitments,
depth: 15,
leavesPerNode: 2,
};
}
const circuitPath = rlnPath.circuitFilePath;
const zkeyFilePath = rlnPath.zkeyFilePath;
try {
const toastId = toast("Generating RLN proof...", {
type: "info",
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: false,
});
const proof = await client?.rlnProof(
externalNullifier,
signal,
circuitPath,
zkeyFilePath,
storageAddressOrArtifacts,
rlnIdentifierHex,
);
console.log("RLN proof generated successfully!", proof);
toast("RLN proof generated successfully!", { type: "success" });
toast.dismiss(toastId);
} catch (e) {
toast("Error while generating RLN proof!", { type: "error" });
console.error(e);
}
};
const getIdentityCommitment = useCallback(async () => {
const idCommitment = await client?.getActiveIdentity();
if (!idCommitment) {
return;
}
toast(`Getting Identity Commitment successfully! ${idCommitment}`, { type: "success" });
setIdentityCommitment(idCommitment);
}, [client, setIdentityCommitment]);
const initClient = useCallback(async () => {
const { zkpr } = window;
if (!zkpr) {
log.warn("zkpr is not defined");
return;
}
const client = await zkpr.connect();
setClient(client);
setIsLocked(false);
}, [setClient, setIsLocked]);
const onIdentityChanged = useCallback(
(idCommitment: unknown) => {
setIdentityCommitment(idCommitment as string);
},
[setIdentityCommitment],
);
const onLogin = useCallback(() => {
setIsLocked(false);
getIdentityCommitment();
}, [setIsLocked, getIdentityCommitment]);
const onLogout = useCallback(() => {
setIdentityCommitment("");
setIsLocked(true);
}, [setIdentityCommitment, setIsLocked]);
useEffect(() => {
if (!client) {
initClient();
}
}, [client, initClient]);
useEffect(() => {
if (!client) {
return undefined;
}
getIdentityCommitment();
client?.on("login", onLogin);
client?.on("identityChanged", onIdentityChanged);
client?.on("logout", onLogout);
return () => {
client?.off("login", onLogin);
client?.off("identityChanged", onIdentityChanged);
client?.off("logout", onLogout);
};
}, [Boolean(client), onLogout, onIdentityChanged, onLogin]);
if (!client || isLocked) {
return <NotConnected onClick={initClient} />;
}
if (!identityCommitment) {
return <NoActiveIDCommitment />;
}
return (
<div>
<div>
<h2>Semaphore</h2>
<button onClick={() => genSemaphoreProof(MerkleProofType.STORAGE_ADDRESS)}>
Generate proof from Merkle proof storage address
</button>{" "}
<br />
<br />
<button onClick={() => genSemaphoreProof(MerkleProofType.ARTIFACTS)}>
Generate proof from Merkle proof artifacts
</button>
</div>
<hr />
<div>
<h2>RLN</h2>
<button onClick={() => genRLNProof(MerkleProofType.STORAGE_ADDRESS)}>
Generate proof from Merkle proof storage address
</button>{" "}
<br />
<br />
<button onClick={() => genRLNProof(MerkleProofType.ARTIFACTS)}>
Generate proof from Merkle proof artifacts
</button>
</div>
<hr />
<div>
<h2>Get identity commitment</h2>
<button onClick={() => getIdentityCommitment()}>Get</button> <br />
<br />
</div>
<hr />
<div>
<h2>Identity commitment for active identity:</h2>
<p>{identityCommitment}</p>
</div>
<ToastContainer newestOnTop={true} />
</div>
);
}
const root = document.getElementById("root");
ReactDOM.render(<App />, root);