<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged zk</title>
<link>https://coderlegion.com/tag/zk</link>
<description>Powered by Question2Answer</description>
<item>
<title>Beyond Identity: Rethinking Trust Infrastructure Through Zero-Knowledge Verification</title>
<link>https://coderlegion.com/20276/beyond-identity-rethinking-trust-infrastructure-through-zero-knowledge-verification</link>
<description>&lt;h3 id=&quot;abstract-&quot;&gt;Abstract:&lt;/h3&gt;
&lt;p&gt;Trust on the internet has traditionally relied on centralized authorities, public credentials, and extensive disclosure of personal information. Whether applying for a job, verifying an academic qualification, or proving professional experience, users are often required to reveal significantly more information than necessary.&lt;/p&gt;
&lt;p&gt;While exploring emerging solutions in this space, I came across two interesting approaches. GitHired focuses on proving technical credibility through actual work rather than resume claims, while Fhenix explores privacy-preserving computation through Fully Homomorphic Encryption (FHE). Both projects address different dimensions of trust, yet neither fully solves the challenge of verifiable identity and credential ownership.&lt;/p&gt;
&lt;p&gt;This observation led to the conceptualization of ZenProof, a privacy-preserving trust infrastructure that combines decentralized identity standards, verifiable credentials, distributed storage, and Zero-Knowledge Proofs to enable trust verification without exposing sensitive information.&lt;/p&gt;
&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;/h3&gt;
&lt;p&gt;One question kept bothering me throughout my exploration of Web3 identity systems:&lt;/p&gt;
&lt;p&gt;Why do we reveal everything just to prove one thing?&lt;/p&gt;
&lt;p&gt;A university graduate only wants to prove they possess a degree.&lt;/p&gt;
&lt;p&gt;A developer only wants to prove they possess a skill.&lt;/p&gt;
&lt;p&gt;A professional only wants to prove they hold a certification.&lt;/p&gt;
&lt;p&gt;Yet modern systems require complete disclosure of personal information, documents, and credentials to establish trust.&lt;/p&gt;
&lt;p&gt;As digital ecosystems continue to evolve, trust itself has become one of the internet's most valuable resources. However, existing verification systems remain heavily dependent on centralized databases and excessive information sharing.&lt;/p&gt;
&lt;p&gt;This led me to investigate whether trust could be verified differently.&lt;/p&gt;
&lt;p&gt;Not through disclosure.&lt;/p&gt;
&lt;p&gt;But through cryptographic proof.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8u4m94dwo9a31xsa78sp.jpg&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;2-existing-approaches&quot;&gt;2. Existing Approaches&lt;/h3&gt;
&lt;h3 id=&quot;githired-trust-through-proof-of-work&quot;&gt;GitHired: Trust Through Proof of Work&lt;/h3&gt;
&lt;p&gt;One of the most interesting platforms I encountered was GitHired.&lt;/p&gt;
&lt;p&gt;Instead of evaluating candidates through traditional resumes, GitHired analyzes actual GitHub contributions, project complexity, and development activity. The platform operates on a simple but powerful philosophy:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Trust what developers build, not what they claim.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This approach significantly improves hiring accuracy by emphasizing demonstrable work over self-reported qualifications. GitHired's model focuses on proof-of-work rather than keyword matching or resume-based filtering.&lt;/p&gt;
&lt;p&gt;However, while GitHired addresses credibility, it does not directly solve privacy or identity ownership challenges.&lt;/p&gt;
&lt;h3 id=&quot;fhenix-trust-through-privacy&quot;&gt;Fhenix: Trust Through Privacy&lt;/h3&gt;
&lt;p&gt;Fhenix approaches the problem from a completely different direction.&lt;/p&gt;
&lt;p&gt;Using Fully Homomorphic Encryption (FHE), Fhenix enables computation on encrypted data without revealing the underlying information. This allows developers to build confidential smart contracts while preserving privacy throughout execution.&lt;/p&gt;
&lt;p&gt;The technology represents a major advancement in privacy-preserving blockchain infrastructure.&lt;/p&gt;
&lt;p&gt;However, its primary focus is confidential computation rather than decentralized credential verification.&lt;/p&gt;
&lt;h3 id=&quot;3-identifying-the-research-gap&quot;&gt;3. Identifying the Research Gap&lt;/h3&gt;
&lt;p&gt;While studying both systems, I noticed something interesting.&lt;/p&gt;
&lt;p&gt;GitHired solves credibility.&lt;/p&gt;
&lt;p&gt;Fhenix solves privacy.&lt;/p&gt;
&lt;p&gt;But neither directly addresses a broader challenge:&lt;/p&gt;
&lt;p&gt;How can individuals prove qualifications, skills, certifications, or achievements without exposing the underlying data itself?&lt;/p&gt;
&lt;p&gt;This gap became the foundation of ZenProof.&lt;/p&gt;
&lt;h3 id=&quot;4-introducing-zenproof&quot;&gt;4. Introducing ZenProof&lt;/h3&gt;
&lt;p&gt;ZenProof is envisioned as a privacy-preserving trust infrastructure designed around a simple principle:&lt;/p&gt;
&lt;p&gt;Prove the claim, not the data.&lt;/p&gt;
&lt;p&gt;Instead of sharing certificates, users share cryptographic proofs.&lt;/p&gt;
&lt;p&gt;Instead of exposing identities, users verify legitimacy.&lt;/p&gt;
&lt;p&gt;Instead of relying on centralized verification systems, trust becomes mathematically verifiable.&lt;/p&gt;
&lt;p&gt;To achieve this, ZenProof combines:&lt;/p&gt;
&lt;p&gt;W3C Decentralized Identifiers (DIDs)&lt;br&gt;
Verifiable Credentials&lt;br&gt;
IPFS-based decentralized storage&lt;br&gt;
zk-SNARK proof generation&lt;br&gt;
Selective disclosure mechanisms&lt;/p&gt;
&lt;p&gt;Together, these technologies create an environment where verification becomes possible without sacrificing privacy.&lt;/p&gt;
&lt;h3 id=&quot;5-why-this-matters&quot;&gt;5. Why This Matters&lt;/h3&gt;
&lt;p&gt;As AI-generated content, deepfakes, forged certificates, and fake resumes become increasingly common, proving authenticity will become one of the internet's most important challenges.&lt;/p&gt;
&lt;p&gt;The future will not belong to systems that collect the most data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p81qy1twqujpz5hxkm2l.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;It will belong to systems that require the least data while providing the strongest guarantees of trust.&lt;/p&gt;
&lt;p&gt;That is the vision behind ZenProof.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/20276/beyond-identity-rethinking-trust-infrastructure-through-zero-knowledge-verification</guid>
<pubDate>Thu, 11 Jun 2026 10:15:45 +0000</pubDate>
</item>
<item>
<title>A Clear and Working Example of Zero-Knowledge Proofs in a Real Web3 Application</title>
<link>https://coderlegion.com/4349/a-clear-and-working-example-of-zero-knowledge-proofs-in-a-real-web3-application</link>
<description>&lt;p&gt;Zero-knowledge proofs (ZKPs) allow someone to prove they know or did something — without revealing what it was. A specific type of ZKP called a &lt;strong&gt;zk-SNARK&lt;/strong&gt; (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) enables compact and fast proofs that can be verified on-chain.&lt;/p&gt;
&lt;p&gt;Writing ZK circuits manually can be complex, but &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://zokrates.github.io/&quot;&gt;ZoKrates&lt;/a&gt;&lt;/strong&gt; makes it much easier. It provides a high-level language and tooling to compile circuits, generate proofs, and export Solidity verifiers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/melanke/zk-voting-sample/main/working.gif&quot; alt=&quot;Working Demo&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this tutorial, we’ll use ZoKrates to build a &lt;strong&gt;simple private voting example&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;️ A user will commit to their vote (1 or 2) using a secret nonce and the Poseidon hash function.&lt;br&gt;
 Later, they’ll prove (without revealing their vote or nonce) that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The vote was valid (1 or 2), and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It matches a previously published commitment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ll generate the proof entirely in JavaScript and verify it on-chain — all using a local setup with &lt;strong&gt;scaffold-eth-2&lt;/strong&gt;, a powerful framework for building Ethereum dApps.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ This is a minimal example to help you understand the flow. It’s not a full voting system — just a small step into the zk world.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-step-0-install-zokrates&quot;&gt;️ Step 0: Install ZoKrates&lt;/h3&gt;
&lt;p&gt;On Linux/macOS, install with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -LSfs get.zokrat.es | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ On &lt;strong&gt;Windows&lt;/strong&gt;, make sure to install and run inside &lt;strong&gt;WSL&lt;/strong&gt; (Windows Subsystem for Linux), or you’ll face compatibility issues.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check it's working:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;zokrates --help
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;-step-1-bootstrap-your-dapp&quot;&gt;⚙️ Step 1: Bootstrap Your dApp&lt;/h3&gt;
&lt;p&gt;Use &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/scaffold-eth/scaffold-eth-2&quot;&gt;scaffold-eth-2&lt;/a&gt; — the fastest way to start building full-stack dApps.&lt;/p&gt;
&lt;p&gt;Initialize the project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-eth@latest # we are using foundry, but hardhat works too
cd my-zk-vote  # open the project's directory
yarn           # install all dependencies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add ZK dependencies on NextJS package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd packages\nextjs # go to nextjs directory
yarn add circomlibjs zokrates-js # add zk frontend dependencies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start development servers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd ..\..       # go back to the root directory
yarn chain     # start local blockchain
yarn deploy    # deploy contracts
yarn start     # launch frontend
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-write-the-circuit&quot;&gt;Step 2: Write the Circuit&lt;/h3&gt;
&lt;p&gt;You can see the circuit as a way to validate secret information. Each information marked as &lt;code&gt;private&lt;/code&gt; will remain secret and can be validated against other public arguments. &lt;/p&gt;
&lt;p&gt;Create a file at &lt;code&gt;packages/foundry/contracts/vote.zok&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zokrates&quot;&gt;import &quot;hashes/poseidon/poseidon.zok&quot;;

def main(private field vote, private field nonce, field commitment) -&amp;gt; bool {
    assert(vote == 1 || vote == 2);
    field hash = poseidon([vote, nonce]);
    assert(hash == commitment);
    return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;what-this-does-&quot;&gt;What this does:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enforces that the vote must be &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; — a simple rule for this example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hashes the vote and a secret nonce using &lt;strong&gt;Poseidon&lt;/strong&gt;, then checks that it matches the provided commitment — proving the commitment corresponds to a valid vote.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;Why Poseidon? It’s a hash function designed for zero-knowledge circuits — much faster and cheaper to verify in zk-SNARKs than SHA256 or Keccak.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-generate-the-commitment-in-javascript&quot;&gt;Step 3: Generate the Commitment in JavaScript&lt;/h3&gt;
&lt;p&gt;Create a helper file at &lt;code&gt;packages/nextjs/utils/zkVote.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { buildPoseidon } from &quot;circomlibjs&quot;;

export async function generateCommitment(vote: number, nonce: bigint): Promise&amp;lt;string&amp;gt; {
  const poseidon = await buildPoseidon();
  const commitment = poseidon([BigInt(vote), nonce]);
  return poseidon.F.toString(commitment);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; You can now copy &lt;code&gt;vote&lt;/code&gt;, &lt;code&gt;nonce&lt;/code&gt;, and &lt;code&gt;commitment&lt;/code&gt; into the &lt;a rel=&quot;nofollow&quot; href=&quot;https://play.zokrat.es/&quot;&gt;ZoKrates Playground&lt;/a&gt; to test your circuit manually.&lt;/p&gt;
&lt;p&gt; Tip: You can use the commands below to quickly generate a commitment to test on the playground:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd packages/nextjs
npx --package typescript tsc utils/zkVote.ts --target es2020 --module commonjs --outDir dist --esModuleInterop
node -e &quot;require('./dist/zkVote.js').generateCommitment(2, 123456789n).then(console.log);&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-compile-the-circuit&quot;&gt;Step 4: Compile the Circuit&lt;/h3&gt;
&lt;p&gt;Run this from your project root:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd packages/foundry/contracts
zokrates compile -i vote.zok
zokrates setup
zokrates export-verifier
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;This will produce a &lt;code&gt;verifier.sol&lt;/code&gt; file you can use on-chain.&lt;/li&gt;
&lt;li&gt;Move &lt;code&gt;proving.key&lt;/code&gt; and &lt;code&gt;verification.key&lt;/code&gt; to &lt;code&gt;packages/nextjs/public&lt;/code&gt; so it's available in the frontend, don't worry, these keys are not private.&lt;/li&gt;
&lt;li&gt;You can delete &lt;code&gt;abi.json&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt; and &lt;code&gt;out.r1cs&lt;/code&gt; files, if you want.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-5-add-the-verifier-to-your-app&quot;&gt;Step 5: Add the Verifier to Your App&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create `packages/foundry/script/DeployVerifier.s.sol:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-sol&quot;&gt;pragma solidity ^0.8.19;

import &quot;./DeployHelpers.s.sol&quot;;
import &quot;../contracts/verifier.sol&quot;;

contract DeployVerifier is ScaffoldETHDeploy {
    function run() external ScaffoldEthDeployerRunner {
        new Verifier();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Edit `packages/foundry/script/Deploy.s.sol:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-sol&quot;&gt;pragma solidity ^0.8.19;

import &quot;./DeployHelpers.s.sol&quot;;
import { DeployYourContract } from &quot;./DeployYourContract.s.sol&quot;;
import { DeployVerifier } from &quot;./DeployVerifier.s.sol&quot;;

contract DeployScript is ScaffoldETHDeploy {
    function run() external {
        DeployYourContract deployYourContract = new DeployYourContract();
        deployYourContract.run();

        DeployVerifier deployVerifier = new DeployVerifier();
        deployVerifier.run();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Then redeploy everything:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-6-generate-the-proof-in-the-frontend&quot;&gt;Step 6: Generate the Proof in the Frontend&lt;/h3&gt;
&lt;p&gt;Continue in &lt;code&gt;packages/nextjs/utils/zkVote.ts&lt;/code&gt; and add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { initialize } from &quot;zokrates-js&quot;;

let cachedKeypair: any = null;

async function loadKeypair() {
  if (!cachedKeypair) {
    const provingKeyResponse = await fetch(&quot;/proving.key&quot;);
    const provingKeyBuffer = await provingKeyResponse.arrayBuffer();

    const verificationKeyResponse = await fetch(&quot;/verification.key&quot;);
    const verificationKeyBuffer = await verificationKeyResponse.arrayBuffer();

    const provingKeyUint8 = new Uint8Array(provingKeyBuffer);
    const verificationKeyUint8 = new Uint8Array(verificationKeyBuffer);

    cachedKeypair = {
      pk: provingKeyUint8,
      vk: verificationKeyUint8,
    };
  }
  return cachedKeypair;
}

export type Proof = {
  proof: {
    a: { X: bigint; Y: bigint };
    b: { X: readonly [bigint, bigint]; Y: readonly [bigint, bigint] };
    c: { X: bigint; Y: bigint };
  };
  inputs: readonly [bigint, bigint];
};

function formatProof(rawProof: any): Proof {
  const { a, b, c } = rawProof.proof;

  const toBigTuple = (arr: string[]) =&amp;gt; [BigInt(arr[0]), BigInt(arr[1])] as const;

  return {
    proof: {
      a: { X: BigInt(a[0]), Y: BigInt(a[1]) },
      b: { X: toBigTuple(b[0]), Y: toBigTuple(b[1]) },
      c: { X: BigInt(c[0]), Y: BigInt(c[1]) },
    },
    inputs: toBigTuple(rawProof.inputs),
  };
}

export async function proveVote(vote: number, nonce: bigint, commitment: string): Promise&amp;lt;Proof&amp;gt; {
  const zokrates = await initialize();
  const artifacts = zokrates.compile(`
  import &quot;hashes/poseidon/poseidon.zok&quot;;

  def main(private field vote, private field nonce, field commitment) -&amp;gt; bool {
      assert(vote == 1 || vote == 2);
      field hash = poseidon([vote, nonce]);
      assert(hash == commitment);
      return true;
  }
      `);
  const keypair = await loadKeypair();

  const { witness } = zokrates.computeWitness(artifacts, [vote.toString(), nonce.toString(), commitment]);
  const rawProof = zokrates.generateProof(artifacts.program, witness, keypair.pk);
  return formatProof(rawProof);
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important method here is &lt;code&gt;proveVote&lt;/code&gt;, it will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;initialize zokrates&lt;/li&gt;
&lt;li&gt;compile the circuit&lt;/li&gt;
&lt;li&gt;load the keypairs&lt;/li&gt;
&lt;li&gt;compute witness using the arguments of the method&lt;/li&gt;
&lt;li&gt;generate the proof with the compiled circuit, the witness and the proving key.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-7-verify-the-proof-on-chain&quot;&gt;Step 7: Verify the Proof On-Chain&lt;/h3&gt;
&lt;p&gt;Call your Verifier contract from the frontend on a Nextjs page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;&quot;use client&quot;;

import { useRef, useState } from &quot;react&quot;;
import type { NextPage } from &quot;next&quot;;
import { toast } from &quot;react-hot-toast&quot;;
import { useScaffoldReadContract } from &quot;~~/hooks/scaffold-eth&quot;;
import { Proof, generateCommitment, proveVote } from &quot;~~/utils/zkVote&quot;;

const Home: NextPage = () =&amp;gt; {
  // generate a random nonce
  const nonceRef = useRef&amp;lt;bigint&amp;gt;(BigInt(Date.now() + Math.floor(Math.random() * 1000)));

  // state for the vote, the commitment, the proof, and the loading state
  const [vote, setVote] = useState&amp;lt;string&amp;gt;(&quot;&quot;);
  const [commitment, setCommitment] = useState&amp;lt;string&amp;gt;();
  const [proof, setProof] = useState&amp;lt;Proof | null&amp;gt;(null);
  const [isLoading, setIsLoading] = useState(false);

  // verify the proof onchain once you have the proof
  const { data: isVerified } = useScaffoldReadContract({
    contractName: &quot;Verifier&quot;,
    functionName: &quot;verifyTx&quot;,
    args: [proof?.proof, proof?.inputs],
    query: {
      enabled: !!proof,
    },
  });

  // generate the commitment when the user clicks the button
  const handleVote = async () =&amp;gt; {
    if (!vote) return;

    setIsLoading(true);
    try {
      const voteNumber = Number(vote);
      const newCommitment = await generateCommitment(voteNumber, nonceRef.current);
      setCommitment(newCommitment);
    } catch (error) {
      toast.error(&quot;Error generating commitment: &quot; + (error as Error).message);
    } finally {
      setIsLoading(false);
    }
  };

  // prove the vote when the user clicks the button
  const handleProve = async () =&amp;gt; {
    if (!vote || !commitment) return;

    setIsLoading(true);

    try {
      const voteNumber = Number(vote);
      const newProof = await proveVote(voteNumber, nonceRef.current, commitment);
      setProof(newProof);
    } catch {
      toast.error(&quot;Impossible to prove&quot;);
      setProof(null);
    } finally {
      setIsLoading(false);
    }
  };
  
  // render your page...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can check the whole code of the page component in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/melanke/zk-voting-sample/blob/main/packages/nextjs/app/page.tsx&quot;&gt;repository Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To test your ZK dApp locally, just open &lt;a rel=&quot;nofollow&quot; href=&quot;http://localhost:3000&quot;&gt;http://localhost:3000&lt;/a&gt; in your browser.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;In this example, we called the &lt;code&gt;Verifier&lt;/code&gt; contract directly from the frontend. That’s useful for learning — but in a real-world application, it’s not the pattern you’d use.&lt;/p&gt;
&lt;p&gt;Instead, your main contract (e.g. a voting contract, identity manager, or game logic) would receive the proof and &lt;strong&gt;internally call the Verifier contract&lt;/strong&gt; to validate it before proceeding with any logic.&lt;/p&gt;
&lt;p&gt;This architecture gives you control and flexibility:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function submitVote(
  uint[2] calldata a,
  uint[2][2] calldata b,
  uint[2] calldata c,
  uint[] calldata input
) external {
  require(verifier.verifyTx(a, b, c, input), &quot;Invalid proof&quot;);
  // continue with vote counting, recording, etc
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;what-you-could-build-with-this&quot;&gt;What You Could Build with This&lt;/h4&gt;
&lt;p&gt;This approach opens doors to powerful applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anonymous voting&lt;/strong&gt;: prove your vote was valid without revealing it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private whitelists&lt;/strong&gt;: prove membership in a group (via Merkle root) without showing which one&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private randomness&lt;/strong&gt;: commit to a number, later prove its properties (e.g., in a fair lottery)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Game actions&lt;/strong&gt;: prove you played by the rules without revealing your strategy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Credential systems&lt;/strong&gt;: prove you hold a credential without disclosing your identity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Zero-knowledge isn’t just privacy — it’s about &lt;strong&gt;integrity without exposure&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you're exploring zero-knowledge or building real-world dApps, feel free to connect — I'd love to exchange ideas.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Written by Gil, a fullstack developer with 15+ years of experience, passionate about practical architecture, clean UX, and blockchain-powered applications.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/4349/a-clear-and-working-example-of-zero-knowledge-proofs-in-a-real-web3-application</guid>
<pubDate>Wed, 30 Jul 2025 11:25:49 +0000</pubDate>
</item>
</channel>
</rss>