From 43754c1e7117a1a0e4b93617663e8898b47fb7ba Mon Sep 17 00:00:00 2001 From: shreyas-londhe Date: Mon, 3 Jun 2024 20:44:41 +0530 Subject: [PATCH] feat: frontend example complete --- .DS_Store | Bin 0 -> 6148 bytes circuits/.DS_Store | Bin 0 -> 6148 bytes circuits/halo2/.DS_Store | Bin 0 -> 6148 bytes .../halo2/example-frontend/package-lock.json | 8 +- circuits/halo2/example-frontend/package.json | 2 +- .../example-frontend/src/app/nullifier.ts | 2 +- .../halo2/example-frontend/src/app/page.tsx | 218 +++++++++++------- .../halo2/example-frontend/src/app/utils.ts | 39 ++++ .../halo2/example-frontend/src/app/worker.ts | 45 ++-- circuits/halo2/wasm/src/lib.rs | 2 + 10 files changed, 217 insertions(+), 99 deletions(-) create mode 100644 .DS_Store create mode 100644 circuits/.DS_Store create mode 100644 circuits/halo2/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4959978255caf25913c4c0ecd44d01c693f2e89f GIT binary patch literal 6148 zcmeHK%Wl&^6upy%#!0D^1qe1sme__6QYfm}q-nCK1T1O<3qT=GqTqDa{S z|G+P>CPF?+~XOad3lIPwCBSIL{%bk;Ecrzk}Hhs**C0U zO0ENidWWPsg(PV}H}?{O#xekgs^^X6~}um4bn zT%MDFIiWDe`I6%}*cSq{GoU#zp*R~a?))jr?37r4C18G_$CTl#cSIor{wH7 zZ@u?&;U)cK9=H3m*ZlNC%Fw^a_x+c_Xwj?QIFeD)52Ddb5rW|eA#Yv<(NHehavlw1 z#r1TBQ+CR|>aFE+ukpC%9yC`qcX`lk)ZB-A`>R#ixq0{glat;!oJ8^iYlGbo+o7^u zgBS1-nGG4vy;&5>=oEF#tI!#S;~XACsu`r3Qj(ME6XMdtQ35BXd$drjNiO>PM)XrU z#-MlUIeFC0Mi;mr>35gu1d)f-p=ZE426~ufsLAm;H92pA+9phrBh#^{$+m>Y89 zDUxQEQ_L|n=@IQ`+ftJx&DcgOdh(90R4E;c#;jc`U?!=vb6I3_RspMkRX{1g`-2N- zY#Cf@R9goUbp-$xQLGGk{#{^>Yp`W-tr0aap{YPk73PW|G#%xxiE9~LYt(cS=JFv- z%fj4HglZk{cU3rvmPVUe1*`&D1-A5KmCyg~@9+Ovl6|rYSOxwo1w^sqb=vqObGB}L x9G|r={2iQ)d;G75J+P`~*FQ(dGaE literal 0 HcmV?d00001 diff --git a/circuits/.DS_Store b/circuits/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ca65b36e652507849a097cace15660c3481919eb GIT binary patch literal 6148 zcmeHK%}xR_5T5cQON0PAKne0l=$vLaet=CZ_Z{QDx{hHsqrq+d0Q82Ch!DZMUH45t|DjxV@-0tas zu+>JFo2xKxsZmW0<5pkCdZxq4JNZUob3Cq;4vVr{o)qP{S}qmke&t{?$vYd{yGQ4Z zhv+d@&w6qoa2sn`vp9tptjtXP$?L_Dito`njhK2eG6T#2Gw=r(ut%4(`Ul3!Lu3Y+ zfuCi7&IgG~=vqt+>Z1b-{RBXyYor#e(`Ariq(#?aVi0>!gb777p~5~fgb7Exw0^F| z#GnZWVILpD{#n=;iqL<@?@R3t!ZpYxGr$bYGmtjT0_FeH)Bv3A%eu~90!XmADZ;rv#nH(`-yGCxHux3dE|c_>&|v+b^iKzu;``mlAV!~hqR zf>Uioe?1r7Msz`==CHK5-}N>fs?m2zlV+TnG9TBb3~1K2PXRL(-M#I5HTyeql>m$8HV&k}_Mnyqpj$`HUQG69i8R~p?fPulKMwGzpkARZFW>$f}s=#+j CP_B>w literal 0 HcmV?d00001 diff --git a/circuits/halo2/example-frontend/package-lock.json b/circuits/halo2/example-frontend/package-lock.json index ea2ce1a..b3a7396 100644 --- a/circuits/halo2/example-frontend/package-lock.json +++ b/circuits/halo2/example-frontend/package-lock.json @@ -11,7 +11,7 @@ "axios": "^1.6.8", "idb": "^8.0.0", "next": "14.2.2", - "plume-wasm": "^0.1.5", + "plume-wasm": "^0.1.6", "react": "^18", "react-dom": "^18" }, @@ -3582,9 +3582,9 @@ } }, "node_modules/plume-wasm": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/plume-wasm/-/plume-wasm-0.1.5.tgz", - "integrity": "sha512-9AzHRp7Vzq5HkBPxA0m1sjtpJYMBIfhDGeJmHHWM47rDH7zu2Ncm9sY9Nj0YOPPl/T84jNo8Bf8QAJ9S3pBHbg==" + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/plume-wasm/-/plume-wasm-0.1.6.tgz", + "integrity": "sha512-yJmP++coAjiR0YAEM20bznjRuK7iinCrZGxe/Ngs4YevDggJF8GZggjSaHUTk+buOfS5bnnhZEw1qRYZn+blcA==" }, "node_modules/possible-typed-array-names": { "version": "1.0.0", diff --git a/circuits/halo2/example-frontend/package.json b/circuits/halo2/example-frontend/package.json index 197466a..bd95318 100644 --- a/circuits/halo2/example-frontend/package.json +++ b/circuits/halo2/example-frontend/package.json @@ -12,7 +12,7 @@ "axios": "^1.6.8", "idb": "^8.0.0", "next": "14.2.2", - "plume-wasm": "^0.1.5", + "plume-wasm": "^0.1.6", "react": "^18", "react-dom": "^18" }, diff --git a/circuits/halo2/example-frontend/src/app/nullifier.ts b/circuits/halo2/example-frontend/src/app/nullifier.ts index 2fcd23d..0bc2b1f 100644 --- a/circuits/halo2/example-frontend/src/app/nullifier.ts +++ b/circuits/halo2/example-frontend/src/app/nullifier.ts @@ -19,7 +19,7 @@ export async function generateNullifier(): Promise { }) )[0]; - let message = "CLAIM MY MONI!!"; + let message = "CLAIM MY MONIII"; let nullifier = await window.ethereum.request({ method: "eth_getPlumeSignature", diff --git a/circuits/halo2/example-frontend/src/app/page.tsx b/circuits/halo2/example-frontend/src/app/page.tsx index b67beb7..8231141 100644 --- a/circuits/halo2/example-frontend/src/app/page.tsx +++ b/circuits/halo2/example-frontend/src/app/page.tsx @@ -8,9 +8,10 @@ import { generateNullifier } from "./nullifier"; export default function Home() { const [isRunning, setIsRunning] = useState(false); const [worker, setWorker] = useState(null); - const [isLoading, setIsLoading] = useState(true); + const [isLoading, setIsLoading] = useState(false); + const [selectedOption, setSelectedOption] = useState(null); - useEffect(() => { + const initializeWorker = () => { const newWorker = new Worker(new URL("./worker.ts", import.meta.url), { type: "module", }); @@ -24,60 +25,78 @@ export default function Home() { } }; setWorker(newWorker); + }; - return () => newWorker.terminate(); + useEffect(() => { + initializeWorker(); + return () => worker?.terminate(); }, []); useEffect(() => { - const downloadAndStoreObject = async () => { - try { - const db = await openDB("MyDatabase", 1, { - upgrade(db) { - db.createObjectStore("DataStore"); - }, - }); + if (selectedOption) { + initializeWorker(); + const downloadAndStoreObject = async () => { + setIsLoading(true); + try { + const db = await openDB("MyDatabase", 1, { + upgrade(db) { + db.createObjectStore("DataStore"); + }, + }); - const storedVk = await db.get("DataStore", "vk"); - const storedPk = await db.get("DataStore", "pk"); + const vkKey = + selectedOption === "signature" ? "vk_signature" : "vk_merkle"; + const pkKey = + selectedOption === "signature" ? "pk_signature" : "pk_merkle"; - if (storedVk && storedPk) { - console.log( - "Verifying key and proving key already stored in Indexeddb", - ); - setIsLoading(false); - } else { - console.log("Downloading and storing verifying key and proving key"); - const vk = await fetchAndConvertToUint8Array( - "https://storage.googleapis.com/plume-keys/plume_verify_vk_15.bin", - ); - const pk = await fetchAndConvertToUint8Array( - "https://storage.googleapis.com/plume-keys/plume_verify_pk_15.bin", - ); - - await db.put("DataStore", vk, "vk"); - await db.put("DataStore", pk, "pk"); + const storedVk = await db.get("DataStore", vkKey); + const storedPk = await db.get("DataStore", pkKey); + + if (storedVk && storedPk) { + console.log("Keys already stored in Indexeddb"); + setIsLoading(false); + } else { + console.log("Downloading and storing keys"); + const vkUrl = + selectedOption === "signature" + ? "https://storage.googleapis.com/plume-keys/plume_verify_vk_15.bin" + : "https://storage.googleapis.com/plume-keys/plume_merkle_verify_vk_15_8.bin"; + const pkUrl = + selectedOption === "signature" + ? "https://storage.googleapis.com/plume-keys/plume_verify_pk_15.bin" + : "https://storage.googleapis.com/plume-keys/plume_merkle_verify_pk_15_8.bin"; + + const vk = await fetchAndConvertToUint8Array(vkUrl); + const pk = await fetchAndConvertToUint8Array(pkUrl); + + await db.put("DataStore", vk, vkKey); + await db.put("DataStore", pk, pkKey); + setIsLoading(false); + console.log("Keys downloaded and stored in Indexeddb"); + } + } catch (error) { + console.error("Error downloading and storing object:", error); setIsLoading(false); - console.log( - "Verifying key and proving key downloaded and stored in Indexeddb", - ); } - } catch (error) { - console.error("Error downloading and storing object:", error); - setIsLoading(false); - } - }; + }; - downloadAndStoreObject(); - }, []); + downloadAndStoreObject(); + } + }, [selectedOption]); const runMain = async () => { - if (worker) { + if (worker && selectedOption) { setIsRunning(true); try { const db = await openDB("MyDatabase", 1); - const storedVk = await db.get("DataStore", "vk"); - const storedPk = await db.get("DataStore", "pk"); + const vkKey = + selectedOption === "signature" ? "vk_signature" : "vk_merkle"; + const pkKey = + selectedOption === "signature" ? "pk_signature" : "pk_merkle"; + + const storedVk = await db.get("DataStore", vkKey); + const storedPk = await db.get("DataStore", pkKey); if (storedVk && storedPk) { const plume = await generateNullifier(); @@ -85,10 +104,11 @@ export default function Home() { provingKey: storedPk, verifyingKey: storedVk, plume, + option: selectedOption, }; worker.postMessage({ action: "runMain", data: data }); } else { - console.error("Verifying key and proving key not found in Indexeddb"); + console.error("Keys not found in Indexeddb"); setIsRunning(false); } } catch (error) { @@ -100,48 +120,88 @@ export default function Home() { return (
-
+

PLUME Verification in WASM

- + +
+
+ +
{isLoading && (

Downloading proving and verifying keys... diff --git a/circuits/halo2/example-frontend/src/app/utils.ts b/circuits/halo2/example-frontend/src/app/utils.ts index 3f8f290..7aca3cf 100644 --- a/circuits/halo2/example-frontend/src/app/utils.ts +++ b/circuits/halo2/example-frontend/src/app/utils.ts @@ -39,3 +39,42 @@ export const getKzgParams = async (k: number) => { `https://axiom-crypto.s3.amazonaws.com/challenge_0085/kzg_bn254_${k}.srs`, ); }; + +export const getMerkleData = (merkleTree: string[][], leafIndex: number) => { + const proof = []; + const proofHelper = []; + let index = leafIndex; + + for (let level = 0; level < merkleTree.length - 1; level++) { + const isRightNode = index % 2 === 1; + const siblingIndex = isRightNode ? index - 1 : index + 1; + + if (siblingIndex < merkleTree[level].length) { + proof.push(merkleTree[level][siblingIndex]); + proofHelper.push(isRightNode ? "0x0" : "0x1"); + } + + index = Math.floor(index / 2); + } + + const root = merkleTree[merkleTree.length - 1][0]; + + return { proof, proofHelper, root }; +}; + +export const fetchMerkleData = async (url: string, leafIndex: number) => { + const response = await fetch(url); + const data = await response.json(); + + let { + proof: merkleProof, + proofHelper, + root, + } = getMerkleData(data, leafIndex); + + console.log("proof", merkleProof); + console.log("proofHelper", proofHelper); + console.log("root", root); + + return { merkleProof, proofHelper, root }; +}; diff --git a/circuits/halo2/example-frontend/src/app/worker.ts b/circuits/halo2/example-frontend/src/app/worker.ts index 125dcac..71a6922 100644 --- a/circuits/halo2/example-frontend/src/app/worker.ts +++ b/circuits/halo2/example-frontend/src/app/worker.ts @@ -1,13 +1,15 @@ -import { getKzgParams } from "./utils"; +import { fetchMerkleData, getKzgParams } from "./utils"; import init, { initThreadPool, initPanicHook, Halo2Wasm, - PlumeVerify, + Circuit, } from "plume-wasm"; self.onmessage = async (e) => { - if (e.data.action === "runMain") { + const { action, data } = e.data; + if (action === "runMain") { + const { provingKey, verifyingKey, plume, option } = data; try { await init(); console.log("Wasm initialized"); @@ -31,17 +33,32 @@ self.onmessage = async (e) => { }); console.log("Halo2Wasm configured"); - const plumeVerify = new PlumeVerify(halo2wasm); - console.log("PlumeVerify instance created"); + const circuit = new Circuit(halo2wasm); + console.log("circuit instance created"); - plumeVerify.run({ - nullifier: e.data.data.plume.nullifier, - s: e.data.data.plume.s, - c: e.data.data.plume.c, - message: e.data.data.plume.message, - publicKey: e.data.data.plume.publicKey, + circuit.plumeVerify({ + nullifier: plume.nullifier, + s: plume.s, + c: plume.c, + message: plume.message, + publicKey: plume.publicKey, }); - console.log("PlumeVerify run completed"); + console.log("PlumeVerify completed"); + + if (option === "merkle") { + const { merkleProof, proofHelper, root } = await fetchMerkleData( + "https://storage.googleapis.com/plume-keys/merkle_tree_8.json", + 0, + ); + + circuit.merkleVerify({ + root, + publicKey: plume.publicKey, + proof: merkleProof, + proofHelper, + }); + console.log("MerkleVerify completed"); + } halo2wasm.useInstances(); console.log("Using instances"); @@ -57,10 +74,10 @@ self.onmessage = async (e) => { console.error("Invalid KZG params format"); } - halo2wasm.loadVk(e.data.data.verifyingKey); + halo2wasm.loadVk(verifyingKey); console.log("Verification key loaded"); - halo2wasm.loadPk(e.data.data.provingKey); + halo2wasm.loadPk(provingKey); console.log("Proving key loaded"); const proofStart = performance.now(); diff --git a/circuits/halo2/wasm/src/lib.rs b/circuits/halo2/wasm/src/lib.rs index 9bbac42..d749779 100644 --- a/circuits/halo2/wasm/src/lib.rs +++ b/circuits/halo2/wasm/src/lib.rs @@ -69,6 +69,7 @@ impl Circuit { } } + #[wasm_bindgen(js_name = plumeVerify)] pub fn plume_verify(&mut self, input: PlumeVerifyInput) { let nullifier = parse_compressed_point(input.nullifier); let s = parse_scalar(input.s); @@ -115,6 +116,7 @@ impl Circuit { builder_borrow.assigned_instances[0].append(&mut nullifier.y().limbs().to_vec()); } + #[wasm_bindgen(js_name = merkleVerify)] pub fn merkle_verify(&mut self, input: MerkleVerifyInput) { let pk = parse_compressed_point(input.public_key); let root = parse_fr(input.root);