Skip to content

Commit

Permalink
feat: update twitter verifier circuit to user pubkey hash (test failing)
Browse files Browse the repository at this point in the history
  • Loading branch information
saleel committed Aug 24, 2023
1 parent 6e8ddb4 commit 9f9d57a
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 87 deletions.
1 change: 1 addition & 0 deletions packages/contracts/DKIMRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "@openzeppelin/contracts/access/Ownable.sol";

/**
A Registry that store the hash(dkim_public_key) for each domain
The hash is calculated by taking Poseidon of DKIM key split into 9 chunks of 242 bits each
*/
contract DKIMRegistry is Ownable {
// Use constants for popular domains to save gas on reads
Expand Down
2 changes: 1 addition & 1 deletion packages/twitter-verifier-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ src = 'src'
out = 'out'
libs = [ 'lib' ] # See more config options https://github.com/foundry-rs/foundry/tree/master/config
viaIR = true
allow_paths = ['../../node_modules', '../../node_modules/@zk-email/contracts/utils']
allow_paths = ['../../node_modules', '../../node_modules/@zk-email/contracts']
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "forge-std/console.sol";
import "forge-std/Script.sol";
import "@zk-email/contracts/DKIMRegistry.sol";
import "../src/TwitterEmailHandler.sol";
import "../src/Groth16VerifierTwitter.sol";

Expand All @@ -20,8 +20,8 @@ contract Deploy is Script, Test {
uint256 sk = getPrivateKey();
vm.startBroadcast(sk);
Verifier proofVerifier = new Verifier();
MailServer mailServer = new MailServer();
VerifiedTwitterEmail testVerifier = new VerifiedTwitterEmail(proofVerifier, mailServer);
DKIMRegistry dkimRegistry = new DKIMRegistry();
VerifiedTwitterEmail testVerifier = new VerifiedTwitterEmail(proofVerifier, dkimRegistry);
vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import "@zk-email/contracts/EmailVerifier.sol";

//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Expand Down Expand Up @@ -180,7 +178,7 @@ library Pairing {
}
}

contract Verifier is Groth16Verifier {
contract Verifier {
using Pairing for *;

struct VerifyingKey {
Expand Down Expand Up @@ -322,7 +320,7 @@ contract Verifier is Groth16Verifier {
}

/// @return r bool true if proof is valid
function verifyProof(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[] memory input) public view returns (bool r) {
function verifyProof(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[5] memory input) public view returns (bool r) {
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
Expand Down
91 changes: 58 additions & 33 deletions packages/twitter-verifier-contracts/src/TwitterEmailHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,35 @@ pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "forge-std/console.sol";
// import "./utils/StringUtils.sol";
import "@zk-email/contracts/DKIMRegistry.sol";
import "./utils/StringUtils.sol";
import "./utils/NFTSVG.sol";
import {Verifier} from "./Groth16VerifierTwitter.sol";
// import "./utils/MailServer.sol";
import "@zk-email/contracts/EmailVerifier.sol";
import { Verifier } from "./Groth16VerifierTwitter.sol";

contract VerifiedTwitterEmail is ERC721Enumerable, EmailVerifier {

contract VerifiedTwitterEmail is ERC721Enumerable {
using Counters for Counters.Counter;
using StringUtils for *;
using NFTSVG for *;

Counters.Counter private tokenCounter;

uint16 public constant msg_len = 21; // header + body
uint16 public constant bytesInPackedBytes = 7; // 7 bytes in a packed item returned from circom
uint32 public constant body_len = 3;
uint8 public constant rsa_modulus_chunks_len = 17;
uint256 public constant header_len = msg_len - body_len;
uint256 public constant addressIndexInSignals = msg_len - 1;
string constant domain = "twitter.com";

uint16 public constant signalLength = 5; // length of signals array
uint32 public constant pubKeyHashIndexInSignals = 0; // index of DKIM public key hash in signals array
uint32 public constant usernameIndexInSignals = 1; // index of packed twitter username in signals array
uint32 public constant usernameLengthInSignals = 3; // length of packed twitter username in signals array
uint32 public constant addressIndexInSignals = 4; // index of ethereum address in signals array

Counters.Counter private tokenCounter;
DKIMRegistry dkimRegistry;
Verifier public immutable verifier;

mapping(string => uint256[rsa_modulus_chunks_len]) public verifiedMailserverKeys;
mapping(uint256 => string) public tokenIDToName;
string constant domain = "twitter.com";
// MailServer mailServer;
// Verifier public immutable verifier;

constructor(Verifier v, MailServer m) EmailVerifier(v, m) ERC721("VerifiedEmail", "VerifiedEmail") {
// verifier = v;
// mailServer = m;
require(rsa_modulus_chunks_len + body_len + 1 == msg_len, "Variable counts are wrong!");
constructor(Verifier v, DKIMRegistry d) ERC721("VerifiedEmail", "VerifiedEmail") {
verifier = v;
dkimRegistry = d;
}

function tokenDesc(uint256 tokenId) public view returns (string memory) {
Expand All @@ -60,15 +58,16 @@ contract VerifiedTwitterEmail is ERC721Enumerable, EmailVerifier {
// Usage: require(_domainCheck(senderBytes, domainStrings), "Invalid domain");
}

function mint(uint256[8] memory proof, uint256[] memory signals)
public
{
/// Mint a token proving twitter ownership by verifying proof of email
/// @param proof ZK proof of the circuit - a[2], b[4] and c[2] encoded in series
/// @param signals Public signals of the circuit. First item is pubkey_hash, next 3 are twitter username, the last one is etherum address
function mint(uint256[8] memory proof, uint256[5] memory signals) public {
// TODO no invalid signal check yet, which is fine since the zk proof does it
// Checks: Verify proof and check signals
// require(signals[0] == 1337, "invalid signals");

// 3 public signals are the masked packed message bytes, 17 are the modulus.
// public signals are the masked packed message bytes, and hash of public key.

// Check eth address committed to in proof matches msg.sender, to avoid replayability
// require(address(uint160(signals[addressIndexInSignals])) == msg.sender, "Invalid address");

Expand All @@ -77,24 +76,50 @@ contract VerifiedTwitterEmail is ERC721Enumerable, EmailVerifier {
// We will upload the version with these domain checks soon!
// require(_domainCheck(headerSignals), "Invalid domain");

// Verify the DKIM public key hash stored on-chain matches the one used in circuit
bytes32 dkimPublicKeyHashInCircuit = bytes32(signals[pubKeyHashIndexInSignals]);
bytes32 dkimPublicKeyHashOnChain = dkimRegistry.getDKIMPublicKeyHash(domain);

require(dkimPublicKeyHashOnChain != bytes32(0), "dkim for domain not found");

require(dkimPublicKeyHashInCircuit == dkimPublicKeyHashOnChain, "invalid signature");

// Veiry RSA and proof
verifyEmail(domain, proof, signals, body_len, rsa_modulus_chunks_len);
require(
verifier.verifyProof(
[proof[0], proof[1]],
[[proof[2], proof[3]], [proof[4], proof[5]]],
[proof[6], proof[7]],
signals
),
"Invalid Proof"
);

uint256[] memory bodySignals = new uint256[](body_len);
for (uint256 i = 0; i < body_len; i++) {
uint256[] memory bodySignals = new uint256[](usernameLengthInSignals);
for (uint256 i = 0; i < usernameLengthInSignals; i++) {
bodySignals[i] = signals[i];
}

// Effects: Mint token
uint256 tokenId = tokenCounter.current() + 1;
string memory messageBytes =
StringUtils.convertPackedBytesToString(bodySignals, bytesInPackedBytes * body_len, bytesInPackedBytes);
string memory messageBytes = StringUtils.convertPackedBytesToString(
bodySignals,
bytesInPackedBytes * usernameLengthInSignals,
bytesInPackedBytes
);
tokenIDToName[tokenId] = messageBytes;
_mint(msg.sender, tokenId);
tokenCounter.increment();
}

function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal {
require(from == address(0), "Cannot transfer - VerifiedEmail is soulbound");
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal {
require(
from == address(0),
"Cannot transfer - VerifiedEmail is soulbound"
);
}
}
61 changes: 15 additions & 46 deletions packages/twitter-verifier-contracts/src/test/TestTwitter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "forge-std/console.sol";
import "@zk-email/contracts/DKIMRegistry.sol";
import "../TwitterEmailHandler.sol";
import "../Groth16VerifierTwitter.sol";

Expand All @@ -11,15 +12,15 @@ contract TwitterUtilsTest is Test {
address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; // Hardcoded address of the VM from foundry

Verifier proofVerifier;
MailServer mailServer;
DKIMRegistry dkimRegistry;
VerifiedTwitterEmail testVerifier;

uint16 public constant packSize = 7;

function setUp() public {
proofVerifier = new Verifier();
mailServer = new MailServer();
testVerifier = new VerifiedTwitterEmail(proofVerifier, mailServer);
dkimRegistry = new DKIMRegistry();
testVerifier = new VerifiedTwitterEmail(proofVerifier, dkimRegistry);
}

// function testMint() public {
Expand Down Expand Up @@ -63,28 +64,12 @@ contract TwitterUtilsTest is Test {

// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
function testVerifyTestEmail() public {
uint256[] memory publicSignals = new uint256[](21);
publicSignals[0] = 28557011619965818;
publicSignals[1] = 1818845549;
publicSignals[2] = 0;
publicSignals[3] = 1634582323953821262989958727173988295;
publicSignals[4] = 1938094444722442142315201757874145583;
publicSignals[5] = 375300260153333632727697921604599470;
publicSignals[6] = 1369658125109277828425429339149824874;
publicSignals[7] = 1589384595547333389911397650751436647;
publicSignals[8] = 1428144289938431173655248321840778928;
publicSignals[9] = 1919508490085653366961918211405731923;
publicSignals[10] = 2358009612379481320362782200045159837;
publicSignals[11] = 518833500408858308962881361452944175;
publicSignals[12] = 1163210548821508924802510293967109414;
publicSignals[13] = 1361351910698751746280135795885107181;
publicSignals[14] = 1445969488612593115566934629427756345;
publicSignals[15] = 2457340995040159831545380614838948388;
publicSignals[16] = 2612807374136932899648418365680887439;
publicSignals[17] = 16021263889082005631675788949457422;
publicSignals[18] = 299744519975649772895460843780023483;
publicSignals[19] = 3933359104846508935112096715593287;
publicSignals[20] = 1;
uint256[5] memory publicSignals;
publicSignals[0] = 5857406240302475676709141738935898448223932090884766940073913110146444539372;
publicSignals[1] = 28557011619965818;
publicSignals[2] = 1818845549;
publicSignals[3] = 0;
publicSignals[4] = 1;

uint256[2] memory proof_a = [
19927878014774420599335762081097643265718718256586894795640382494403322204498,
Expand Down Expand Up @@ -130,28 +115,12 @@ contract TwitterUtilsTest is Test {

// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
function testVerifyYushEmail() public {
uint256[] memory publicSignals = new uint256[](21);
publicSignals[0] = 113659471951225;
publicSignals[1] = 0;
uint256[5] memory publicSignals;
publicSignals[0] = 5857406240302475676709141738935898448223932090884766940073913110146444539372; // DKIM hash
publicSignals[1] = 113659471951225;
publicSignals[2] = 0;
publicSignals[3] = 1634582323953821262989958727173988295;
publicSignals[4] = 1938094444722442142315201757874145583;
publicSignals[5] = 375300260153333632727697921604599470;
publicSignals[6] = 1369658125109277828425429339149824874;
publicSignals[7] = 1589384595547333389911397650751436647;
publicSignals[8] = 1428144289938431173655248321840778928;
publicSignals[9] = 1919508490085653366961918211405731923;
publicSignals[10] = 2358009612379481320362782200045159837;
publicSignals[11] = 518833500408858308962881361452944175;
publicSignals[12] = 1163210548821508924802510293967109414;
publicSignals[13] = 1361351910698751746280135795885107181;
publicSignals[14] = 1445969488612593115566934629427756345;
publicSignals[15] = 2457340995040159831545380614838948388;
publicSignals[16] = 2612807374136932899648418365680887439;
publicSignals[17] = 16021263889082005631675788949457422;
publicSignals[18] = 299744519975649772895460843780023483;
publicSignals[19] = 3933359104846508935112096715593287;
publicSignals[20] = 556307310756571904145052207427031380052712977221;
publicSignals[3] = 0;
publicSignals[4] = 556307310756571904145052207427031380052712977221; // Wallet address

// TODO switch order
uint256[2] memory proof_a = [
Expand Down

0 comments on commit 9f9d57a

Please sign in to comment.