Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
signorecello committed Feb 13, 2024
1 parent 65d82aa commit cdf911d
Show file tree
Hide file tree
Showing 14 changed files with 1,574 additions and 1,261 deletions.
File renamed without changes.

Large diffs are not rendered by default.

File renamed without changes.
3 changes: 0 additions & 3 deletions vite-hardhat/circuits/Prover.toml

This file was deleted.

2 changes: 0 additions & 2 deletions vite-hardhat/circuits/Verifier.toml

This file was deleted.

148 changes: 18 additions & 130 deletions vite-hardhat/components/index.tsx
Original file line number Diff line number Diff line change
@@ -1,146 +1,34 @@
import {
useState,
useEffect,
ChangeEvent,
} from 'react';

import { toast } from 'react-toastify';
import { useState } from 'react';
import React from 'react';

import { Noir } from '@noir-lang/noir_js';
import { BarretenbergBackend } from '@noir-lang/backend_barretenberg';
import { CompiledCircuit, ProofData } from '@noir-lang/types';
import { compile, createFileManager } from '@noir-lang/noir_wasm';

import { useAccount, useConnect, useContractWrite } from 'wagmi';
import { contractCallConfig } from '../utils/wagmi.jsx';
import { bytesToHex } from 'viem';

export async function getFile(file_path: string): Promise<ReadableStream<Uint8Array>> {
const file_url = new URL(file_path, import.meta.url);
const response = await fetch(file_url);

if (!response.ok) throw new Error('Network response was not OK');

return response.body as ReadableStream<Uint8Array>;
}

async function getCircuit(name: string) {
const fm = createFileManager('/');
fm.writeFile('./src/main.nr', await getFile(`../circuits/${name}/src/${name}.nr`));
fm.writeFile('./Nargo.toml', await getFile(`../circuits/${name}/Nargo.toml`));
const result = await compile(fm);
if (!('program' in result)) {
throw new Error('Compilation failed');
}
return result.program as CompiledCircuit;
}
import { useOnChainVerification } from '../hooks/useOnChainVerification.jsx';
import { useProofGeneration } from '../hooks/useProofGeneration.jsx';

function Component() {
const [input, setInput] = useState({ x: 0, y: 0 });
const [proof, setProof] = useState<ProofData>();
const [noir, setNoir] = useState<Noir | null>(null);
const [backend, setBackend] = useState<BarretenbergBackend | null>(null);

const { isConnected } = useAccount();
const { connect, connectors } = useConnect();
const [input, setInput] = useState<{ x: string; y: string } | undefined>();
const { proofData } = useProofGeneration(input);
// useOnChainVerification(proofData);

const { write, data, error, isLoading, isError } = useContractWrite({
...contractCallConfig,
functionName: 'verify',
});

// Handles input state
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const submit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (e.target) setInput({ ...input, [e.target.name]: e.target.value });
};
const elements = e.currentTarget.elements;
if (!elements) return;

// Calculates proof
const calculateProof = async () => {
const calc = new Promise(async (resolve, reject) => {
const { proof, publicInputs } = await noir!.generateFinalProof(input);
console.log('Proof created: ', proof);
setProof({ proof, publicInputs });
resolve(proof);
});
toast.promise(calc, {
pending: 'Calculating proof...',
success: 'Proof calculated!',
error: 'Error calculating proof',
});
};

const verifyProof = async () => {
const verifyOffChain = new Promise(async (resolve, reject) => {
if (proof) {
const verification = await noir!.verifyFinalProof({
proof: proof.proof,
publicInputs: proof.publicInputs,
});
console.log('Proof verified: ', verification);
resolve(verification);
}
});

toast.promise(verifyOffChain, {
pending: 'Verifying proof off-chain...',
success: 'Proof verified off-chain!',
error: 'Error verifying proof',
});
const x = elements.namedItem('x') as HTMLInputElement;
const y = elements.namedItem('y') as HTMLInputElement;

connectors.map(c => c.ready && connect({ connector: c }));

if (proof) {
write?.({
args: [bytesToHex(proof.proof), proof.publicInputs],
});
}
setInput({ x: x.value, y: y.value });
};

useEffect(() => {
if (proof) {
verifyProof();
return () => {
backend!.destroy();
};
}
}, [proof]);

useEffect(() => {
if (data) toast.success('Proof verified on-chain!');
}, [data]);

const initNoir = async () => {
const circuit = await getCircuit('main');

// @ts-ignore
const backend = new BarretenbergBackend(circuit.program, { threads: 8 });
setBackend(backend);

// @ts-ignore
const noir = new Noir(circuit.program, backend);
await toast.promise(noir.init(), {
pending: 'Initializing Noir...',
success: 'Noir initialized!',
error: 'Error initializing Noir',
});
setNoir(noir);
};

useEffect(() => {
initNoir();
}, []);

return (
<div className="container">
<form className="container" onSubmit={submit}>
<h1>Example starter</h1>
<h2>This circuit checks that x and y are different</h2>
<h2>This circuit checks that x and y are different (yey!)</h2>
<p>Try it!</p>
<input name="x" type={'number'} onChange={handleChange} value={input.x} />
<input name="y" type={'number'} onChange={handleChange} value={input.y} />
<button onClick={calculateProof}>Calculate proof</button>
</div>
<input name="x" type="text" />
<input name="y" type="text" />
<button type="submit">Calculate proof</button>
</form>
);
}

Expand Down
2 changes: 1 addition & 1 deletion vite-hardhat/hardhat.config.cts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const config: HardhatUserConfig = {
},
},
paths: {
sources: './circuits/contract/noirstarter',
sources: './circuit',
},
};

Expand Down
58 changes: 58 additions & 0 deletions vite-hardhat/hooks/useOnChainVerification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ProofData } from '@noir-lang/types';
import { useAccount, useConnect, useContractRead } from 'wagmi';
import { contractCallConfig } from '../utils/wagmi.jsx';
import { bytesToHex } from 'viem';
import { useEffect, useState } from 'react';
import { Id, toast } from 'react-toastify';

export function useOnChainVerification(proofData?: ProofData) {
const { connect, connectors } = useConnect();
const { isConnected } = useAccount();
const [args, setArgs] = useState<[string, string[]] | undefined>();

const { data, error } = useContractRead({
...contractCallConfig,
functionName: 'verify',
args,
});

const [onChainToast, setOnChainToast] = useState<Id>(0);

useEffect(() => {
if (!isConnected) {
console.log("not connected, won't attempt on-chain verification");
}
if (!proofData || !isConnected) {
return;
}

setArgs([bytesToHex(proofData.proof), proofData.publicInputs]);

if (!onChainToast)
setOnChainToast(toast.loading('Verifying proof on-chain', { autoClose: 10000 }));
}, [proofData]);

useEffect(() => {
if (!isConnected) {
connectors.map(c => c.ready && connect({ connector: c }));
}
}, [isConnected]);

useEffect(() => {
console.log(data);
if (data) {
toast.update(onChainToast, {
type: 'success',
render: 'Proof verified on-chain!',
isLoading: false,
});
} else if (error) {
toast.update(onChainToast, {
type: 'error',
render: 'Error verifying proof on-chain!',
isLoading: false,
});
console.error(error);
}
}, [data, error]);
}
43 changes: 43 additions & 0 deletions vite-hardhat/hooks/useProofGeneration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { toast } from 'react-toastify';
import { useEffect, useState } from 'react';
import { getCircuit } from '../utils/compile.js';
import { BarretenbergBackend, ProofData } from '@noir-lang/backend_barretenberg';
import { Noir } from '@noir-lang/noir_js';

export function useProofGeneration(inputs?: { [key: string]: string }) {
const [proofData, setProofData] = useState<ProofData | undefined>();

const proofGeneration = async () => {
if (!inputs) return;
const circuit = await getCircuit();
const backend = new BarretenbergBackend(circuit, { threads: navigator.hardwareConcurrency });
const noir = new Noir(circuit, backend);

await toast.promise(noir.init, {
pending: 'Initializing Noir...',
success: 'Noir initialized!',
error: 'Error initializing Noir',
});

const data = await toast.promise(noir.generateFinalProof(inputs), {
pending: 'Generating proof',
success: 'Proof generated',
error: 'Error generating proof',
});

const res = await toast.promise(noir.verifyFinalProof(data), {
pending: 'Verifying proof off-chain',
success: 'Proof verified off-chain',
error: 'Error verifying proof off-chain',
});

console.log(res);
};

useEffect(() => {
if (!inputs) return;
proofGeneration();
}, [inputs]);

return { proofData };
}
1 change: 0 additions & 1 deletion vite-hardhat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,5 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
<Component />
<ToastContainer />
</InitWasm>
,
</Providers>,
);
11 changes: 6 additions & 5 deletions vite-hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
"type": "module",
"description": "A template repository to get started with writing zero knowledge programs with Noir.",
"scripts": {
"dev": "hardhat compile && yarn deploy && vite",
"prep": "cd circuit && nargo codegen-verifier",
"dev": "yarn prep && hardhat compile && yarn deploy && vite",
"build": "hardhat compile && yarn deploy && vite build",
"preview": "vite preview",
"deploy": "hardhat compile && NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat run --network ${NETWORK} scripts/deploy.ts",
"test": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat test"
},
"dependencies": {
"@noir-lang/backend_barretenberg": "0.23.0",
"@noir-lang/noir_js": "0.23.0",
"@noir-lang/noir_wasm": "0.23.0",
"@noir-lang/types": "0.23.0",
"@noir-lang/backend_barretenberg": "^0.23.0",
"@noir-lang/noir_js": "^0.23.0",
"@noir-lang/noir_wasm": "^0.23.0",
"@noir-lang/types": "^0.23.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox-viem": "1.0.0",
"@nomicfoundation/hardhat-viem": "1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion vite-hardhat/utils/addresses.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"chainId":31337,"verifier":"0x5fc8d32690cc91d4c39d9d3abcbd16989f875707"}
{"chainId":31337,"verifier":"0x4ed7c70f96b99c776995fb64377f0d4ab3b0e1c1"}
23 changes: 23 additions & 0 deletions vite-hardhat/utils/compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { compile, createFileManager } from '@noir-lang/noir_wasm';
import { CompiledCircuit } from '@noir-lang/types';

export async function getFile(file_path: string): Promise<ReadableStream<Uint8Array>> {
const file_url = new URL(file_path, import.meta.url);
console.log(file_url);
const response = await fetch(file_url);

if (!response.ok) throw new Error('Network response was not OK');

return response.body as ReadableStream<Uint8Array>;
}

export async function getCircuit() {
const fm = createFileManager('/');
fm.writeFile('./src/main.nr', await getFile(`../circuit/src/main.nr`));
fm.writeFile('./Nargo.toml', await getFile(`../circuit/Nargo.toml`));
const result = await compile(fm);
if (!('program' in result)) {
throw new Error('Compilation failed');
}
return result.program as CompiledCircuit;
}
Loading

0 comments on commit cdf911d

Please sign in to comment.