Skip to content

Commit

Permalink
Merge branch 'main' of github.com:Kryha/scaffold-eth-2-noir into feat…
Browse files Browse the repository at this point in the history
…ure/add-steps-component
  • Loading branch information
FilipHarald committed Sep 4, 2023
2 parents d46cd35 + 3633661 commit 2730d30
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 161 deletions.
46 changes: 25 additions & 21 deletions packages/nextjs/pages/example-zk/AgeRestrictedContractExecutor.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CodeText } from "./CodeText";
import SignedStats from "./SignedStats";
import { useScaffoldContractWrite } from "~~/hooks/scaffold-eth";
import { useBirthYearProofsStore } from "~~/services/store/birth-year-proofs";

export const AgeRestrictedContractExecutor = () => {
const proof = useBirthYearProofsStore(state => state.proof);
const setProof = useBirthYearProofsStore(state => state.setProof);

const { writeAsync, isLoading } = useScaffoldContractWrite({
contractName: "BalloonVendor",
Expand All @@ -16,8 +16,8 @@ export const AgeRestrictedContractExecutor = () => {
});

return (
<>
<div className="flex-shrink-0 w-full max-w-5xl px-6 pb-6">
<div className="grid grid-cols-2 gap-6 max-w-7xl">
<div>
<p>
The ballon store is using the same <CodeText text="TokenVendor.sol" /> as the{" "}
<a className="link" href="https://speedrunethereum.com/challenge/token-vendor">
Expand All @@ -26,33 +26,37 @@ export const AgeRestrictedContractExecutor = () => {
, with some additions. They&apos;ve added a function <CodeText text="redeemFreeToken" />, with the{" "}
<CodeText text="onlyKids" />
-modifier. The modifier constructs the public inputs and calls the proof-verifier (
<CodeText text="packages/hardhat/contracts/verifiers/LessThanSignedAge.sol" />
<a href="https://github.com/Kryha/scaffold-eth-2-noir/blob/main/packages/hardhat/contracts/verifiers/LessThanSignedAge.sol">
<CodeText text="packages/hardhat/contracts/verifiers/LessThanSignedAge.sol" />
</a>
). The public inputs is part of the information that was used to generate the proof. They are needed to show
what we are actually proving.
</p>
<p>
Now Alice gets a balloon🎈 <strong>token</strong>, that she can redeem at the store to get an actual ballloon.
</p>
</div>
<div className="card flex-shrink-0 w-full max-w-lg shadow-2xl bg-base-100">
<SignedStats />
<div className="card-body">
<div className="form-control">
<label className="label">
<span className="label-text">Your proof of having the required birth year ✅</span>
</label>
<input
type="text"
placeholder="Proof of required birthyear"
value={proof}
className="input input-bordered"
/>
<div>
<div className="card w-full shadow-2xl bg-base-100">
<div className="card-body">
<div className="form-control">
<label className="label">
<span className="label-text">Your proof of having the required birth year ✅</span>
</label>
<input
type="text"
placeholder="Proof of required birthyear"
value={proof}
className="input input-bordered"
onChange={e => setProof(e.target.value as `0x${string}`)}
/>
</div>
<button className="btn btn-primary mt-6" onClick={() => writeAsync()} disabled={isLoading}>
Get free balloon 🎈
</button>
</div>
<button className="btn btn-primary mt-6" onClick={() => writeAsync()} disabled={isLoading}>
Get free balloon 🎈
</button>
</div>
</div>
</>
</div>
);
};
105 changes: 56 additions & 49 deletions packages/nextjs/pages/example-zk/BirthDateSignature.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState } from "react";
import { CodeText } from "./CodeText";
import SignedStats from "./SignedStats";
import { ethers } from "ethers";
import secp256k1 from "secp256k1";
import { AddressInput } from "~~/components/scaffold-eth/Input/AddressInput";
Expand Down Expand Up @@ -61,8 +60,8 @@ export const BirthDateSignature = ({ aliceDefaultAge }: { aliceDefaultAge: numbe
};

return (
<>
<div className="flex-shrink-0 w-full max-w-5xl px-6 pb-6">
<div className="grid grid-cols-2 gap-6 max-w-7xl">
<div>
<p>
Alice recognizes that, in order for her to not having to share her age with the balloon store, she at least
has to share her age with a third party that the balloon store also can trust. In this case, the balloon store
Expand All @@ -72,9 +71,16 @@ export const BirthDateSignature = ({ aliceDefaultAge }: { aliceDefaultAge: numbe
<p>
When the balloon store implemented their zero knowledge proof solution they made sure that they are using the
same format as the Town Hall for constructing the claim that is being signed📜. In this project the claim
construction can be found in <CodeText text="packages/nextjs/pages/example-zk/BirthDateSignature.tsx" /> (
<CodeText text="signBirthYear" />
) in the FrontEnd and <CodeText text="packages/noir/circuits/LessThanSignedAge/src/main.nr" /> (
construction can be found in{" "}
<a href="https://github.com/Kryha/scaffold-eth-2-noir/blob/main/packages/nextjs/pages/example-zk/BirthDateSignature.tsx">
<CodeText text="packages/nextjs/pages/example-zk/BirthDateSignature.tsx" />
</a>{" "}
(
<CodeText text="signBirthYear" />) in the FrontEnd and{" "}
<a href="https://github.com/Kryha/scaffold-eth-2-noir/blob/main/packages/noir/circuits/LessThanSignedAge/src/main.nr">
<CodeText text="packages/noir/circuits/LessThanSignedAge/src/main.nr" />
</a>{" "}
(
<CodeText text="construct_claim_payload" />) when implemented as a Noir circuit.
</p>
<p>
Expand All @@ -84,51 +90,52 @@ export const BirthDateSignature = ({ aliceDefaultAge }: { aliceDefaultAge: numbe
This can be improved in many ways, but at a minium it should be provided to the UI by a Town Hall employee.
</p>
</div>
<div className="card flex-shrink-0 w-full max-w-lg shadow-2xl bg-base-100">
<SignedStats />
<div className="card-body">
<div className="form-control">
<label className="label">
<span className="label-text">Enter your Ethereum address</span>
</label>
<AddressInput
value={ethereumAddress}
name="personEthereumAddress"
placeholder="Ethereum address"
onChange={(value: string) => setEthereumAddress(value)}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Enter your birth year</span>
</label>
<input
type="number"
placeholder="Birth year"
className="input input-bordered"
value={birthYear}
onChange={e => setBirthYear(e.target.value)}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Third party&apos;s🏛 private key for signing</span>
</label>
<input
type="text"
placeholder="Super secret key"
value={form.thirdPartyPrivateKey}
className="input input-bordered"
onChange={e => setForm({ ...form, thirdPartyPrivateKey: e.target.value })}
/>
</div>
<div className="form-control">
<button className="btn btn-primary mt-6" onClick={handleSubmission}>
Sign birth year 📜
</button>
<div>
<div className="card w-full shadow-2xl bg-base-100">
<div className="card-body">
<div className="form-control">
<label className="label">
<span className="label-text">Enter your Ethereum address</span>
</label>
<AddressInput
value={ethereumAddress}
name="personEthereumAddress"
placeholder="Ethereum address"
onChange={(value: string) => setEthereumAddress(value)}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Enter your birth year</span>
</label>
<input
type="number"
placeholder="Birth year"
className="input input-bordered"
value={birthYear}
onChange={e => setBirthYear(e.target.value)}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Third party&apos;s🏛 private key for signing</span>
</label>
<input
type="text"
placeholder="Super secret key"
value={form.thirdPartyPrivateKey}
className="input input-bordered"
onChange={e => setForm({ ...form, thirdPartyPrivateKey: e.target.value })}
/>
</div>
<div className="form-control">
<button className="btn btn-primary mt-6" onClick={handleSubmission}>
Sign birth year 📜
</button>
</div>
</div>
</div>
</div>
</>
</div>
);
};
148 changes: 76 additions & 72 deletions packages/nextjs/pages/example-zk/GenerateProof.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useState } from "react";
import { CodeText } from "./CodeText";
import SignedStats from "./SignedStats";
import { ethers } from "ethers";
import { AddressInput } from "~~/components/scaffold-eth/Input/AddressInput";
import { ParsedArgs, generateProof } from "~~/hooks/noir/useProofGenerator";
Expand Down Expand Up @@ -91,100 +90,105 @@ export const GenerateProof = ({ requiredBirthYear }: { requiredBirthYear: number
};

return (
<>
<div className="flex-shrink-0 w-full max-w-5xl px-6 pb-6">
<div className="grid grid-cols-2 gap-6 max-w-7xl">
<div>
<p>
One of the reasons that Alice knows that she is not sharing her birth year with anyone is that the proof
generation is open source, and she herself can double check the code. Furthermore she can even generate the
proof✅ herself locally. This is actually what we are doing in this implementation.
</p>
<p>
The proof is generated in the browser in the file{" "}
<CodeText text="packages/nextjs/utils/noir/noirBrowser.ts" />. In this file you can see that the proof is
generated by importing the <CodeText text="aztec/bb.js" /> and <CodeText text="noir-lang/acvm_js" />{" "}
libraries. The proof can also be generated locally, with calling <CodeText text="nargo prove" />. The
predefined circuit ABI code used to generate the proof can be found in{" "}
<CodeText text="packages/nextjs/generated/circuits.json" />, but we could recompile it using{" "}
<CodeText text="nargo compile" />.
<a href="https://github.com/Kryha/scaffold-eth-2-noir/blob/main/packages/nextjs/utils/noir/noirBrowser.ts">
<CodeText text="packages/nextjs/utils/noir/noirBrowser.ts" />
</a>
. In this file you can see that the proof is generated by importing the <CodeText text="aztec/bb.js" /> and{" "}
<CodeText text="noir-lang/acvm_js" /> libraries. The proof can also be generated locally, with calling{" "}
<CodeText text="nargo prove" />. The predefined circuit ABI code used to generate the proof can be found in{" "}
<a href="https://github.com/Kryha/scaffold-eth-2-noir/blob/main/packages/nextjs/generated/circuits.json">
<CodeText text="packages/nextjs/generated/circuits.json" />
</a>
, but we could recompile it using <CodeText text="nargo compile" />.
</p>
<p>
*Note that the &quot;signed age&quot; and &quot;ethereum address&quot;, must be the same as the ones you used
to generate the signed message.
</p>
</div>
<div className="card flex-shrink-0 w-full max-w-lg shadow-2xl bg-base-100">
<SignedStats />
<div className="card-body">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-8">
<div className="form-control">
<label className="label">
<span className="label-text">*Signed birth year</span>
</label>
<input
type="number"
placeholder="Signed birth year"
className="input input-bordered"
value={birthYear}
onChange={e => setBirthYear(e.target.value)}
/>
<div>
<div className="card w-full shadow-2xl bg-base-100">
<div className="card-body">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-8">
<div className="form-control">
<label className="label">
<span className="label-text">*Signed birth year</span>
</label>
<input
type="number"
placeholder="Signed birth year"
className="input input-bordered"
value={birthYear}
onChange={e => setBirthYear(e.target.value)}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Required birth year</span>
</label>
<input
type="number"
placeholder="Required birth year"
className="input input-bordered"
value={form.requiredBirthYear}
onChange={e => setForm({ ...form, requiredBirthYear: Number(e.target.value) })}
/>
</div>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Required birth year</span>
</label>
<input
type="number"
placeholder="Required birth year"
className="input input-bordered"
value={form.requiredBirthYear}
onChange={e => setForm({ ...form, requiredBirthYear: Number(e.target.value) })}
/>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-8">
<div className="form-control">
<label className="label">
<span className="label-text">Birth year signature 📜</span>
</label>
<input
type="text"
placeholder="Birth year signature"
className="input input-bordered"
value={form.proofOfBirthYearSignedMessage}
onChange={e => setForm({ ...form, proofOfBirthYearSignedMessage: e.target.value })}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Public key of signer 🏛</span>
</label>
<input
type="text"
placeholder="Public key of signer"
className="input input-bordered"
value={form.proofOfBirthYearPublicKey}
onChange={e => setForm({ ...form, proofOfBirthYearPublicKey: e.target.value })}
/>
</div>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-8">
<div className="form-control">
<label className="label">
<span className="label-text">Birth year signature 📜</span>
<span className="label-text">*Ethereum address signature</span>
</label>
<input
type="text"
placeholder="Birth year signature"
className="input input-bordered"
value={form.proofOfBirthYearSignedMessage}
onChange={e => setForm({ ...form, proofOfBirthYearSignedMessage: e.target.value })}
<AddressInput
value={ethereumAddress}
name="personEthereumAddress"
placeholder="Ethereum address in signature"
onChange={(value: string) => setEthereumAddress(value)}
/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Public key of signer 🏛</span>
</label>
<input
type="text"
placeholder="Public key of signer"
className="input input-bordered"
value={form.proofOfBirthYearPublicKey}
onChange={e => setForm({ ...form, proofOfBirthYearPublicKey: e.target.value })}
/>
<div className="form-control mt-6">
<button className="btn btn-primary" onClick={handleSubmission} disabled={isProofRunning}>
Generate proof ✅
</button>
</div>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">*Ethereum address signature</span>
</label>
<AddressInput
value={ethereumAddress}
name="personEthereumAddress"
placeholder="Ethereum address in signature"
onChange={(value: string) => setEthereumAddress(value)}
/>
</div>
<div className="form-control mt-6">
<button className="btn btn-primary" onClick={handleSubmission} disabled={isProofRunning}>
Generate proof ✅
</button>
</div>
</div>
</div>
</>
</div>
);
};
Loading

0 comments on commit 2730d30

Please sign in to comment.