Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions contracts/ZKPassportVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

struct ProofVerificationParams {
bytes32 vkeyHash;
bytes proof;
bytes32[] publicInputs;
bytes committedInputs;
uint256[] committedInputCounts;
uint256 validityPeriodInSeconds;
string domain;
string scope;
bool devMode;
}

interface IZKPassportVerifier {
// Verify the proof
function verifyProof(ProofVerificationParams calldata params) external returns (bool verified, bytes32 uniqueIdentifier);

function verifyScopes(bytes32[] calldata publicInputs, string calldata domain, string calldata scope) external view returns (bool);
}

interface IZKVerifier {
function verifyProof(ProofVerificationParams calldata params) external returns (bool verified, bytes32 uniqueIdentifier);
}

/**
* @title ZKPassportVerifier
* @notice Simplified contract to store verification outputs for adult status, country, and gender
*/
contract ZKPassportVerifier {
// Structure to store user verification data
struct Verification {
bool initialized; // Whether the user has set their verification data
bool adult; // Whether user is 18+
string country; // User's country of nationality
string gender; // User's gender
}

// Mapping from user address to their verification data
mapping(address => Verification) public verifications;

// Mapping to track used unique identifiers per wallet
// This prevents cross-wallet correlation while maintaining Sybil resistance
mapping(address => mapping(bytes32 => bool)) public walletUniqueIdentifiers;

// Address of the ZKVerifier contract
IZKVerifier public zkVerifier;

/**
* @notice Constructor that sets the ZKVerifier contract address
* @param _zkVerifier Address of the ZKVerifier contract
*/
constructor(address _zkVerifier) {
require(_zkVerifier != address(0), "Invalid ZKVerifier address");
zkVerifier = IZKVerifier(_zkVerifier);
}

// Event emitted when verification data is updated
event VerificationUpdated(
address indexed user,
bool adult,
string country,
string gender
);

/**
* @notice Update verification data for the sender
* @param adult Whether the sender is 18+
* @param country The sender's country of nationality
* @param gender The sender's gender
* @param params Proof verification parameters
*/
function setVerification(
bool adult,
string calldata country,
string calldata gender,
ProofVerificationParams calldata params
) external {
// Verify the proof first using the ZKVerifier contract
(bool verified, bytes32 uniqueIdentifier) = zkVerifier.verifyProof(params);

// Revert if proof is not valid
require(verified, "Proof verification failed");

// Always enforce wallet-scoped uniqueness
require(!walletUniqueIdentifiers[msg.sender][uniqueIdentifier], "Unique identifier already used by this wallet");

// Mark this unique identifier as used by this wallet
walletUniqueIdentifiers[msg.sender][uniqueIdentifier] = true;

// Store the verification data
verifications[msg.sender] = Verification({
initialized: true,
adult: adult,
country: country,
gender: gender
});

emit VerificationUpdated(msg.sender, adult, country, gender);
}

/**
* @notice Update verification data without requiring a new proof
* @param adult Whether the sender is 18+
* @param country The sender's country of nationality
* @param gender The sender's gender
*/
function updateVerification(
bool adult,
string calldata country,
string calldata gender,
ProofVerificationParams calldata params
) external {
// Verify the proof first using the ZKVerifier contract
(bool verified, bytes32 uniqueIdentifier) = zkVerifier.verifyProof(params);

// Revert if proof is not valid
require(verified, "Proof verification failed");

// Always enforce wallet-scoped uniqueness
require(walletUniqueIdentifiers[msg.sender][uniqueIdentifier], "Unique identifier already used by this wallet");

// Update the verification data
verifications[msg.sender] = Verification({
initialized: true,
adult: adult,
country: country,
gender: gender
});

emit VerificationUpdated(msg.sender, adult, country, gender);
}

/**
* @notice Get verification data for a user
* @param user The address of the user
* @return adult Whether the user is 18+
* @return country The user's country of nationality
* @return gender The user's gender
*/
function getVerification(address user)
external view
returns (bool, bool, string memory, string memory)
{
Verification storage verification = verifications[user];
return (verification.initialized, verification.adult, verification.country, verification.gender);
}
}
25 changes: 25 additions & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import "@nomicfoundation/hardhat-toolbox";
import dotenv from "dotenv";
dotenv.config();

const config = {
solidity: "0.8.20",
networks: {
sepolia: {
url: "https://eth-sepolia.api.onfinality.io/public",
chainId: 11155111,
accounts: [`${process.env.PRIVATE_KEY}`]
}
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
},
paths: {
sources: "./contracts",
tests: "./test",
cache: "./cache",
artifacts: "./artifacts"
},
};

export default config;
Loading