mirror of
https://github.com/AtHeartEngineer/zkp-app-boilerplate.git
synced 2026-01-09 21:37:54 -05:00
add tutorial
This commit is contained in:
@@ -39,3 +39,7 @@
|
||||
yarn workspace app test
|
||||
```
|
||||
|
||||
|
||||
## Example: EdDSA signature rollup
|
||||
|
||||
Let's compress EdDSA signatures into one zk proof! Go to [tutorial!](./TUTORIAL.md)
|
||||
|
||||
670
TUTORIAL.md
Normal file
670
TUTORIAL.md
Normal file
@@ -0,0 +1,670 @@
|
||||
# Tutorial: EdDSA signature rollup
|
||||
|
||||
## Update circuits and test them
|
||||
|
||||
1. Update your circuit
|
||||
|
||||
```diff
|
||||
diff --git a/circuits/circuits/main.circom b/circuits/circuits/main.circom
|
||||
index bc30fa5..6ee8b4a 100644
|
||||
--- a/circuits/circuits/main.circom
|
||||
+++ b/circuits/circuits/main.circom
|
||||
@@ -1,25 +1,29 @@
|
||||
pragma circom 2.0.0;
|
||||
include "../../node_modules/circomlib/circuits/eddsaposeidon.circom";
|
||||
|
||||
-template Sample() {
|
||||
+template Sample(n) {
|
||||
// public
|
||||
signal input M;
|
||||
- signal input Ax;
|
||||
- signal input Ay;
|
||||
+ signal input Ax[n];
|
||||
+ signal input Ay[n];
|
||||
// private
|
||||
- signal input S;
|
||||
- signal input R8x;
|
||||
- signal input R8y;
|
||||
+ signal input S[n];
|
||||
+ signal input R8x[n];
|
||||
+ signal input R8y[n];
|
||||
|
||||
- component verifier = EdDSAPoseidonVerifier();
|
||||
|
||||
- verifier.enabled <== 1;
|
||||
- verifier.Ax <== Ax;
|
||||
- verifier.Ay <== Ay;
|
||||
- verifier.S <== S;
|
||||
- verifier.R8x <== R8x;
|
||||
- verifier.R8y <== R8y;
|
||||
- verifier.M <== M;
|
||||
+ component verifier[n];
|
||||
+ for (var i = 0; i < n; i++) {
|
||||
+ verifier[i] = EdDSAPoseidonVerifier();
|
||||
+ verifier[i].enabled <== 1;
|
||||
+ verifier[i].Ax <== Ax[i];
|
||||
+ verifier[i].Ay <== Ay[i];
|
||||
+ verifier[i].S <== S[i];
|
||||
+ verifier[i].R8x <== R8x[i];
|
||||
+ verifier[i].R8y <== R8y[i];
|
||||
+ verifier[i].M <== M;
|
||||
+ }
|
||||
+
|
||||
}
|
||||
|
||||
-component main { public [M, Ax, Ay] } = Sample();
|
||||
+component main { public [M, Ax, Ay] } = Sample(3);
|
||||
```
|
||||
|
||||
2. Update the client code and the test cases
|
||||
|
||||
Client code:
|
||||
|
||||
```diff
|
||||
diff --git a/circuits/src/client.ts b/circuits/src/client.ts
|
||||
index 946bba7..7270b2c 100644
|
||||
--- a/circuits/src/client.ts
|
||||
+++ b/circuits/src/client.ts
|
||||
@@ -55,11 +55,11 @@ export class ZKPClient {
|
||||
R8y,
|
||||
}: {
|
||||
M: bigint;
|
||||
- Ax: bigint;
|
||||
- Ay: bigint;
|
||||
- S: bigint;
|
||||
- R8x: bigint;
|
||||
- R8y: bigint;
|
||||
+ Ax: bigint[];
|
||||
+ Ay: bigint[];
|
||||
+ S: bigint[];
|
||||
+ R8x: bigint[];
|
||||
+ R8y: bigint[];
|
||||
}): Promise<Proof> {
|
||||
const inputs = {
|
||||
M,
|
||||
```
|
||||
|
||||
Test codes:
|
||||
|
||||
```diff --git a/circuits/test/main.test.ts b/circuits/test/main.test.ts
|
||||
index f85fa9d..4a8a198 100644
|
||||
--- a/circuits/test/main.test.ts
|
||||
+++ b/circuits/test/main.test.ts
|
||||
@@ -11,7 +11,7 @@ describe("Test zkp circuit and scripts", function () {
|
||||
const privKey =
|
||||
"0xABCDEF12ABCDEF12ABCDEF12ABCDEF12ABCDEF12ABCDEF12ABCDEF12ABCDEF12";
|
||||
let client: ZKPClient;
|
||||
- let eddsa: EdDSA;
|
||||
+ let accounts: [EdDSA, EdDSA, EdDSA];
|
||||
beforeEach(async () => {
|
||||
const wasm = fs.readFileSync(
|
||||
path.join(__dirname, "../../circuits/zk/circuits/main_js/main.wasm")
|
||||
@@ -20,21 +20,31 @@ describe("Test zkp circuit and scripts", function () {
|
||||
path.join(__dirname, "../../circuits/zk/zkeys/main.zkey")
|
||||
);
|
||||
client = await new ZKPClient().init(wasm, zkey);
|
||||
- eddsa = await new EdDSA(privKey).init();
|
||||
+ accounts = await Promise.all([
|
||||
+ new EdDSA("0x1111").init(),
|
||||
+ new EdDSA("0x2222").init(),
|
||||
+ new EdDSA("0x3333").init(),
|
||||
+ ]);
|
||||
});
|
||||
it("Should able to prove and verify the zkp", async function () {
|
||||
const message = BigNumber.from(
|
||||
"0xABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00ABCDEF00"
|
||||
);
|
||||
- const signature = await eddsa.sign(message);
|
||||
- expect(await eddsa.verify(message, signature, eddsa.pubKey)).to.eq(true);
|
||||
+ const signatures = await Promise.all(
|
||||
+ accounts.map((acc) => acc.sign(message))
|
||||
+ );
|
||||
+ const result = await Promise.all(
|
||||
+ accounts.map((acc, i) => acc.verify(message, signatures[i], acc.pubKey))
|
||||
+ );
|
||||
+ result.map((res) => expect(res).to.eq(true));
|
||||
+ const F = accounts[0].babyjub.F;
|
||||
const proof = await client.prove({
|
||||
M: message.toBigInt(),
|
||||
- Ax: eddsa.scalarPubKey[0],
|
||||
- Ay: eddsa.scalarPubKey[1],
|
||||
- S: signature.S,
|
||||
- R8x: eddsa.babyjub.F.toObject(signature.R8[0]),
|
||||
- R8y: eddsa.babyjub.F.toObject(signature.R8[1]),
|
||||
+ Ax: accounts.map((acc) => acc.scalarPubKey[0]),
|
||||
+ Ay: accounts.map((acc) => acc.scalarPubKey[1]),
|
||||
+ S: signatures.map((sig) => sig.S),
|
||||
+ R8x: signatures.map((sig) => F.toObject(sig.R8[0])),
|
||||
+ R8y: signatures.map((sig) => F.toObject(sig.R8[1])),
|
||||
});
|
||||
expect(proof).not.to.eq(undefined);
|
||||
});
|
||||
```
|
||||
|
||||
3. Run the test!
|
||||
```shell
|
||||
yarn workspace circuits build
|
||||
yarn workspace circuits test
|
||||
```
|
||||
|
||||
## Update the contract
|
||||
|
||||
1. Update the smart contract
|
||||
|
||||
```diff
|
||||
diff --git a/contracts/contracts/ZkApp.sol b/contracts/contracts/ZkApp.sol
|
||||
index 5168fb7..fcf77a4 100644
|
||||
--- a/contracts/contracts/ZkApp.sol
|
||||
+++ b/contracts/contracts/ZkApp.sol
|
||||
@@ -7,7 +7,7 @@ interface IVerifier {
|
||||
uint256[2] memory a,
|
||||
uint256[2][2] memory b,
|
||||
uint256[2] memory c,
|
||||
- uint256[3] memory input
|
||||
+ uint256[7] memory input
|
||||
) external view returns (bool r);
|
||||
}
|
||||
|
||||
@@ -19,20 +19,35 @@ contract ZkApp {
|
||||
}
|
||||
|
||||
address public immutable verifier;
|
||||
- uint256[3][] public records; // just a sample var
|
||||
+ uint256[2][] public pubKeys;
|
||||
+ uint256[] public signedMessages;
|
||||
|
||||
constructor(address verifier_) {
|
||||
verifier = verifier_;
|
||||
}
|
||||
|
||||
+ function registerKey(uint256[2] memory key) public {
|
||||
+ require(pubKeys.length < 3, "Multisig for 3");
|
||||
+ pubKeys.push(key);
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* @dev This is the sample function
|
||||
*/
|
||||
- function record(uint256[3] memory publicSignals, Proof memory proof)
|
||||
+ function recordSignedMessage(uint256 message, Proof memory proof)
|
||||
public
|
||||
{
|
||||
+ require(pubKeys.length == 3, "Key registration is not done yet.");
|
||||
+ uint256[7] memory publicSignals;
|
||||
+ publicSignals[0] = message;
|
||||
+ publicSignals[1] = pubKeys[0][0];
|
||||
+ publicSignals[2] = pubKeys[1][0];
|
||||
+ publicSignals[3] = pubKeys[2][0];
|
||||
+ publicSignals[4] = pubKeys[0][1];
|
||||
+ publicSignals[5] = pubKeys[1][1];
|
||||
+ publicSignals[6] = pubKeys[2][1];
|
||||
require(verify(publicSignals, proof), "SNARK verification failed");
|
||||
- records.push(publicSignals);
|
||||
+ signedMessages.push(message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +67,7 @@ contract ZkApp {
|
||||
return result;
|
||||
}
|
||||
|
||||
- function totalRecords() public view returns (uint256) {
|
||||
- return records.length;
|
||||
+ function totalSignedMessages() public view returns (uint256) {
|
||||
+ return signedMessages.length;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Update the test code
|
||||
|
||||
```diff
|
||||
diff --git a/contracts/test/ZkApp.test.ts b/contracts/test/ZkApp.test.ts
|
||||
index fd7b69a..07e7875 100644
|
||||
--- a/contracts/test/ZkApp.test.ts
|
||||
+++ b/contracts/test/ZkApp.test.ts
|
||||
@@ -17,13 +17,15 @@ describe("Test ZKP contract", function () {
|
||||
let zkApp: ZkApp;
|
||||
let deployer: SignerWithAddress;
|
||||
let client: ZKPClient;
|
||||
- let eddsa: EdDSA;
|
||||
+ let accounts: [EdDSA, EdDSA, EdDSA];
|
||||
this.beforeEach(async () => {
|
||||
[deployer] = await ethers.getSigners();
|
||||
verifier = await new Verifier__factory(deployer).deploy();
|
||||
- eddsa = await new EdDSA(
|
||||
- "0xABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD"
|
||||
- ).init();
|
||||
+ accounts = await Promise.all([
|
||||
+ new EdDSA("0x1111").init(),
|
||||
+ new EdDSA("0x2222").init(),
|
||||
+ new EdDSA("0x3333").init(),
|
||||
+ ]);
|
||||
zkApp = await new ZkApp__factory(deployer).deploy(verifier.address);
|
||||
client = await new ZKPClient().init(
|
||||
fs.readFileSync(
|
||||
@@ -33,21 +35,24 @@ describe("Test ZKP contract", function () {
|
||||
);
|
||||
});
|
||||
it("Should able to create a zkp and verify them", async function () {
|
||||
- const msg = BigNumber.from("0xabcd");
|
||||
- const signature = await eddsa.sign(msg);
|
||||
+ const message = BigNumber.from("0xabcd");
|
||||
+ const signatures = await Promise.all(
|
||||
+ accounts.map((acc) => acc.sign(message))
|
||||
+ );
|
||||
+ const F = accounts[0].babyjub.F;
|
||||
const proof = await client.prove({
|
||||
- M: msg.toBigInt(),
|
||||
- Ax: eddsa.scalarPubKey[0],
|
||||
- Ay: eddsa.scalarPubKey[1],
|
||||
- S: signature.S,
|
||||
- R8x: eddsa.babyjub.F.toObject(signature.R8[0]),
|
||||
- R8y: eddsa.babyjub.F.toObject(signature.R8[1]),
|
||||
+ M: message.toBigInt(),
|
||||
+ Ax: accounts.map((acc) => acc.scalarPubKey[0]),
|
||||
+ Ay: accounts.map((acc) => acc.scalarPubKey[1]),
|
||||
+ S: signatures.map((sig) => sig.S),
|
||||
+ R8x: signatures.map((sig) => F.toObject(sig.R8[0])),
|
||||
+ R8y: signatures.map((sig) => F.toObject(sig.R8[1])),
|
||||
});
|
||||
- expect(
|
||||
- await zkApp.verify(
|
||||
- [msg, eddsa.scalarPubKey[0], eddsa.scalarPubKey[1]],
|
||||
- proof
|
||||
- )
|
||||
- ).to.eq(true);
|
||||
+ await zkApp.registerKey(accounts[0].scalarPubKey);
|
||||
+ await zkApp.registerKey(accounts[1].scalarPubKey);
|
||||
+ await zkApp.registerKey(accounts[2].scalarPubKey);
|
||||
+ expect(await zkApp.totalSignedMessages()).to.eq(0);
|
||||
+ await zkApp.recordSignedMessage(message, proof);
|
||||
+ expect(await zkApp.totalSignedMessages()).to.eq(1);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
3. Build and run test!
|
||||
```shell
|
||||
yarn workspace contracts build
|
||||
yarn workspace contracts test
|
||||
```
|
||||
|
||||
## Update the UI
|
||||
|
||||
1. Update hooks
|
||||
|
||||
```diff
|
||||
diff --git a/app/src/hooks/useContract.ts b/app/src/hooks/useContract.ts
|
||||
index 38247b6..229e330 100644
|
||||
--- a/app/src/hooks/useContract.ts
|
||||
+++ b/app/src/hooks/useContract.ts
|
||||
@@ -37,24 +37,24 @@ export const useVerifier = (address: string) => {
|
||||
/**
|
||||
* @dev This fetches data every block when the component is mounted
|
||||
*/
|
||||
-export const useTotalRecords = (address: string) => {
|
||||
+export const useTotalSignedMessages = (address: string) => {
|
||||
const zkApp = useZKApp(address);
|
||||
const [totalRecords, setTotalRecords] = useState<BigNumber>();
|
||||
const { library, chainId } = useEthers();
|
||||
|
||||
- const fetchTotalRecords = useCallback(async () => {
|
||||
+ const fetchTotalSignedMessages = useCallback(async () => {
|
||||
if (!zkApp) return;
|
||||
- const _totalRecords = await zkApp.totalRecords();
|
||||
+ const _totalRecords = await zkApp.totalSignedMessages();
|
||||
setTotalRecords(_totalRecords);
|
||||
}, [zkApp]);
|
||||
|
||||
useEffect(() => {
|
||||
- fetchTotalRecords();
|
||||
- library?.on("block", fetchTotalRecords);
|
||||
+ fetchTotalSignedMessages();
|
||||
+ library?.on("block", fetchTotalSignedMessages);
|
||||
return () => {
|
||||
- library?.off("block", fetchTotalRecords);
|
||||
+ library?.off("block", fetchTotalSignedMessages);
|
||||
};
|
||||
- }, [address, library, chainId, fetchTotalRecords]);
|
||||
+ }, [address, library, chainId, fetchTotalSignedMessages]);
|
||||
|
||||
return totalRecords;
|
||||
};
|
||||
@@ -70,17 +70,17 @@ export enum TxState {
|
||||
/**
|
||||
* @dev Contract interfaction example with ZKP
|
||||
*/
|
||||
-export const useRecord = (address: string) => {
|
||||
+export const useRecordSignedmessage = (address: string) => {
|
||||
const zkApp = useZKApp(address);
|
||||
const [txState, setTxState] = useState<TxState>(TxState.NONE);
|
||||
const { library, chainId, account } = useEthers();
|
||||
|
||||
- const record = useCallback(
|
||||
+ const recordSignedMessage = useCallback(
|
||||
async ({
|
||||
publicSignals,
|
||||
proof,
|
||||
}: {
|
||||
- publicSignals: [BigNumberish, BigNumberish, BigNumberish];
|
||||
+ publicSignals: [BigNumberish];
|
||||
proof: {
|
||||
a: [BigNumberish, BigNumberish];
|
||||
b: [[BigNumberish, BigNumberish], [BigNumberish, BigNumberish]];
|
||||
@@ -92,7 +92,7 @@ export const useRecord = (address: string) => {
|
||||
const signer = library.getSigner(account);
|
||||
zkApp
|
||||
.connect(signer)
|
||||
- .record(publicSignals, proof)
|
||||
+ .recordSignedMessage(publicSignals[0], proof)
|
||||
.then((tx) => {
|
||||
setTxState(TxState.PENDING);
|
||||
tx.wait()
|
||||
@@ -103,5 +103,34 @@ export const useRecord = (address: string) => {
|
||||
},
|
||||
[library, chainId, account, zkApp]
|
||||
);
|
||||
- return { txState, record: account ? record : undefined };
|
||||
+ return {
|
||||
+ txState,
|
||||
+ recordSignedMessage: account ? recordSignedMessage : undefined,
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+export const useRegisterKey = (address: string) => {
|
||||
+ const zkApp = useZKApp(address);
|
||||
+ const [txState, setTxState] = useState<TxState>(TxState.NONE);
|
||||
+ const { library, chainId, account } = useEthers();
|
||||
+
|
||||
+ const registerKey = useCallback(
|
||||
+ async ({ pubKey }: { pubKey: [BigNumberish, BigNumberish] }) => {
|
||||
+ if (!zkApp || !account) return;
|
||||
+ if (!library) return;
|
||||
+ const signer = library.getSigner(account);
|
||||
+ zkApp
|
||||
+ .connect(signer)
|
||||
+ .registerKey(pubKey)
|
||||
+ .then((tx) => {
|
||||
+ setTxState(TxState.PENDING);
|
||||
+ tx.wait()
|
||||
+ .then(() => setTxState(TxState.CONFIRMED))
|
||||
+ .catch(() => setTxState(TxState.FAILED));
|
||||
+ })
|
||||
+ .catch(() => setTxState(TxState.CANCELLED));
|
||||
+ },
|
||||
+ [library, chainId, account, zkApp]
|
||||
+ );
|
||||
+ return { txState, registerKey: account ? registerKey : undefined };
|
||||
};
|
||||
```
|
||||
|
||||
1. Add RegisterKey.tsx component
|
||||
|
||||
```typescript
|
||||
import { useRegisterKey } from "../hooks/useContract";
|
||||
|
||||
function RegisterKey({
|
||||
address,
|
||||
pubKey,
|
||||
}: {
|
||||
address: string;
|
||||
pubKey?: [bigint, bigint];
|
||||
}) {
|
||||
const { txState, registerKey } = useRegisterKey(address);
|
||||
return (
|
||||
<div>
|
||||
<p>Tx state: {txState}</p>
|
||||
<button
|
||||
disabled={!registerKey || !pubKey}
|
||||
onClick={() => {
|
||||
if (!pubKey) alert("Pub key is not prepared");
|
||||
else if (!registerKey) alert("Wallet is not connected");
|
||||
else {
|
||||
registerKey({
|
||||
pubKey,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Register pubkey {pubKey}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RegisterKey;
|
||||
```
|
||||
|
||||
1. Update GenZKP.tsx
|
||||
|
||||
```diff
|
||||
diff --git a/app/src/components/GenZKP.tsx b/app/src/components/GenZKP.tsx
|
||||
index 38ae91e..800d80e 100644
|
||||
--- a/app/src/components/GenZKP.tsx
|
||||
+++ b/app/src/components/GenZKP.tsx
|
||||
@@ -3,34 +3,38 @@ import { EdDSASignature } from "circuits/src/eddsa";
|
||||
import useCircuit from "../hooks/useCircuit";
|
||||
|
||||
function GenZKP({
|
||||
- signature,
|
||||
+ signatures,
|
||||
message,
|
||||
- pubKey,
|
||||
+ pubKeys,
|
||||
onResult,
|
||||
}: {
|
||||
message: bigint;
|
||||
- pubKey?: [bigint, bigint];
|
||||
- signature?: EdDSASignature;
|
||||
+ pubKeys?: [bigint, bigint][];
|
||||
+ signatures?: EdDSASignature[];
|
||||
onResult: (proof: Proof) => void;
|
||||
}) {
|
||||
const { client } = useCircuit();
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
- disabled={!client || !pubKey || !signature}
|
||||
+ disabled={!client || !pubKeys || !signatures}
|
||||
onClick={async () => {
|
||||
if (!client) alert("Client is not ready");
|
||||
- else if (!pubKey) alert("EdDSA pubkey is not ready");
|
||||
- else if (!signature) alert("EdDSA signature is not ready");
|
||||
+ else if (!pubKeys) alert("EdDSA pubkey is not ready");
|
||||
+ else if (!signatures) alert("EdDSA signature is not ready");
|
||||
else {
|
||||
client
|
||||
.prove({
|
||||
M: message,
|
||||
- Ax: pubKey[0],
|
||||
- Ay: pubKey[1],
|
||||
- S: signature.S,
|
||||
- R8x: client.babyjub.F.toObject(signature.R8[0]),
|
||||
- R8y: client.babyjub.F.toObject(signature.R8[1]),
|
||||
+ Ax: pubKeys.map((key) => key[0]),
|
||||
+ Ay: pubKeys.map((key) => key[1]),
|
||||
+ S: signatures.map((s) => s.S),
|
||||
+ R8x: signatures.map((signature) =>
|
||||
+ client.babyjub.F.toObject(signature.R8[0])
|
||||
+ ),
|
||||
+ R8y: signatures.map((signature) =>
|
||||
+ client.babyjub.F.toObject(signature.R8[1])
|
||||
+ ),
|
||||
})
|
||||
.then(onResult);
|
||||
}
|
||||
```
|
||||
|
||||
1. Update SendTx.tsx
|
||||
|
||||
```diff
|
||||
diff --git a/app/src/components/SendTx.tsx b/app/src/components/SendTx.tsx
|
||||
index 26f13b3..85fd97f 100644
|
||||
--- a/app/src/components/SendTx.tsx
|
||||
+++ b/app/src/components/SendTx.tsx
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Proof } from "circuits";
|
||||
-import { useRecord } from "../hooks/useContract";
|
||||
+import { useRecordSignedmessage } from "../hooks/useContract";
|
||||
|
||||
function SendTx({
|
||||
address,
|
||||
@@ -7,24 +7,24 @@ function SendTx({
|
||||
proof,
|
||||
}: {
|
||||
address: string;
|
||||
- publicSignals?: [bigint, bigint, bigint];
|
||||
+ publicSignals?: [bigint];
|
||||
proof?: Proof;
|
||||
}) {
|
||||
- const { txState, record } = useRecord(address);
|
||||
+ const { txState, recordSignedMessage } = useRecordSignedmessage(address);
|
||||
return (
|
||||
<div>
|
||||
<p>Tx state: {txState}</p>
|
||||
<p>{!!publicSignals}</p>
|
||||
<p>{!!proof}</p>
|
||||
- <p>{!!record}</p>
|
||||
+ <p>{!!recordSignedMessage}</p>
|
||||
<button
|
||||
- disabled={!publicSignals || !proof || !record}
|
||||
+ disabled={!publicSignals || !proof || !recordSignedMessage}
|
||||
onClick={() => {
|
||||
if (!publicSignals) alert("Public signals are not ready");
|
||||
else if (!proof) alert("ZKP is not ready");
|
||||
- else if (!record) alert("Wallet is not connected");
|
||||
+ else if (!recordSignedMessage) alert("Wallet is not connected");
|
||||
else {
|
||||
- record({
|
||||
+ recordSignedMessage({
|
||||
publicSignals,
|
||||
proof,
|
||||
});
|
||||
```
|
||||
|
||||
1. Update App.tsx
|
||||
|
||||
```diff
|
||||
diff --git a/app/src/App.tsx b/app/src/App.tsx
|
||||
index e26709c..4aee875 100644
|
||||
--- a/app/src/App.tsx
|
||||
+++ b/app/src/App.tsx
|
||||
@@ -1,8 +1,7 @@
|
||||
-import { useEthers, useLocalStorage } from "@usedapp/core";
|
||||
import { Proof } from "circuits";
|
||||
import { EdDSASignature } from "circuits/src/eddsa";
|
||||
import { BigNumber } from "ethers";
|
||||
-import { useEffect, useState } from "react";
|
||||
+import { useState } from "react";
|
||||
import "./App.css";
|
||||
import Connect from "./components/Connect";
|
||||
import GenZKP from "./components/GenZKP";
|
||||
@@ -11,16 +10,25 @@ import SignEdDSA from "./components/SignEdDSA";
|
||||
import Viewer from "./components/Viewer";
|
||||
import useEdDSA from "./hooks/useEdDSA";
|
||||
import Deploy from "./components/Deploy";
|
||||
+import RegisterKey from "./components/RegisterKey";
|
||||
|
||||
// const address = process.env["REACT_APP_CONTRACT_ADDRESS"] as string;
|
||||
// if (typeof address !== "string") throw Error("Configure contract address");
|
||||
const msgToSign = BigNumber.from("0x1234").toBigInt();
|
||||
|
||||
function App() {
|
||||
- const { account } = useEthers();
|
||||
- const privKey = account || undefined;
|
||||
- const { pubKey } = useEdDSA(privKey);
|
||||
- const [eddsaSignature, setEdDSASignature] = useState<EdDSASignature>();
|
||||
+ const privKeys = ["0x1111", "0x2222", "0x3333"];
|
||||
+ const { pubKey: key1 } = useEdDSA(privKeys[0]);
|
||||
+ const { pubKey: key2 } = useEdDSA(privKeys[1]);
|
||||
+ const { pubKey: key3 } = useEdDSA(privKeys[2]);
|
||||
+ const pubKeys = !!key1 && !!key2 && !!key3 ? [key1, key2, key3] : undefined;
|
||||
+ const [eddsaSignature1, setEdDSASignature1] = useState<EdDSASignature>();
|
||||
+ const [eddsaSignature2, setEdDSASignature2] = useState<EdDSASignature>();
|
||||
+ const [eddsaSignature3, setEdDSASignature3] = useState<EdDSASignature>();
|
||||
+ const eddsaSignatures =
|
||||
+ !!eddsaSignature1 && !!eddsaSignature2 && !!eddsaSignature3
|
||||
+ ? [eddsaSignature1, eddsaSignature2, eddsaSignature3]
|
||||
+ : undefined;
|
||||
const [proof, setProof] = useState<Proof>();
|
||||
const [deployed, setDeployed] = useState<string>();
|
||||
return (
|
||||
@@ -32,26 +40,45 @@ function App() {
|
||||
<Deploy onResult={setDeployed} />
|
||||
<h2>Step 3. Check the data fetch from the smart contract</h2>
|
||||
{deployed ? <Viewer address={deployed} /> : <p>Not deployed</p>}
|
||||
- <h2>Step 4. Prepare zkp signals</h2>
|
||||
+ <h2>Step 4. Register EdDSA keys</h2>
|
||||
+ {deployed ? (
|
||||
+ <>
|
||||
+ <RegisterKey address={deployed} pubKey={key1} />
|
||||
+ <RegisterKey address={deployed} pubKey={key2} />
|
||||
+ <RegisterKey address={deployed} pubKey={key3} />
|
||||
+ </>
|
||||
+ ) : (
|
||||
+ <p>Not deployed</p>
|
||||
+ )}
|
||||
+ <h2>Step 5. Prepare EdDSA signatures</h2>
|
||||
+ <SignEdDSA
|
||||
+ privKey={privKeys[0]}
|
||||
+ message={msgToSign}
|
||||
+ onResult={(result) => setEdDSASignature1(result)}
|
||||
+ />
|
||||
+ <p>{eddsaSignature1 ? 'signed': 'None'}</p>
|
||||
+ <SignEdDSA
|
||||
+ privKey={privKeys[1]}
|
||||
+ message={msgToSign}
|
||||
+ onResult={(result) => setEdDSASignature2(result)}
|
||||
+ />
|
||||
+ <p>{eddsaSignature2 ? 'signed': 'None'}</p>
|
||||
<SignEdDSA
|
||||
- privKey={privKey}
|
||||
+ privKey={privKeys[2]}
|
||||
message={msgToSign}
|
||||
- onResult={(result) => setEdDSASignature(result)}
|
||||
+ onResult={(result) => setEdDSASignature3(result)}
|
||||
/>
|
||||
- <h2>Step 5. Compute a zk proof</h2>
|
||||
+ <p>{eddsaSignature3 ? 'signed': 'None'}</p>
|
||||
+ <h2>Step 6. Compute a zk proof</h2>
|
||||
<GenZKP
|
||||
message={msgToSign}
|
||||
- pubKey={pubKey}
|
||||
- signature={eddsaSignature}
|
||||
+ pubKeys={pubKeys}
|
||||
+ signatures={eddsaSignatures}
|
||||
onResult={(result) => setProof(result)}
|
||||
/>
|
||||
- <h2>Step 6. Interact with smart contract using the generated proof</h2>
|
||||
+ <h2>Step 7. Interact with smart contract using the generated proof</h2>
|
||||
{deployed ? (
|
||||
- <SendTx
|
||||
- address={deployed}
|
||||
- publicSignals={pubKey ? [msgToSign, ...pubKey] : undefined}
|
||||
- proof={proof}
|
||||
- />
|
||||
+ <SendTx address={deployed} publicSignals={[msgToSign]} proof={proof} />
|
||||
) : (
|
||||
<p>Not deployed</p>
|
||||
)}
|
||||
```
|
||||
|
||||
1. Update Viewer.tsx
|
||||
|
||||
```diff
|
||||
diff --git a/app/src/components/Viewer.tsx b/app/src/components/Viewer.tsx
|
||||
index 44a29ba..9d2e00f 100644
|
||||
--- a/app/src/components/Viewer.tsx
|
||||
+++ b/app/src/components/Viewer.tsx
|
||||
@@ -1,7 +1,7 @@
|
||||
-import { useTotalRecords } from "../hooks/useContract";
|
||||
+import { useTotalSignedMessages } from "../hooks/useContract";
|
||||
|
||||
function Viewer({ address }: { address: string }) {
|
||||
- const totalRecords = useTotalRecords(address);
|
||||
+ const totalRecords = useTotalSignedMessages(address);
|
||||
return <div>Total records: {totalRecords?.toString() || "fetching..."}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user