Skip to content

Commit

Permalink
basic registration logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Arvolear committed Apr 1, 2024
1 parent 1d07610 commit 53fd6ab
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 47 deletions.
11 changes: 1 addition & 10 deletions contracts/mock/verifiers/VerifierMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@ contract VerifierMock {
uint256[2] calldata pA_,
uint256[2][2] calldata pB_,
uint256[2] calldata pC_,
uint256[4] calldata pubSignal_s
) public view returns (bool) {
return true;
}

function verifyProof(
uint256[2] calldata pA_,
uint256[2][2] calldata pB_,
uint256[2] calldata pC_,
uint256[3] calldata pubSignal_s
uint256[4] calldata pubSignals_
) public view returns (bool) {
return true;
}
Expand Down
43 changes: 26 additions & 17 deletions contracts/registration/Registration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ contract Registration is PoseidonSMT, Initializable {
address public verifier;
bytes32 public icaoMasterTreeMerkleRoot;

mapping(bytes32 => bytes32) public hashedRSAKeyToInternalKey;
mapping(bytes32 => bytes32) public internalKeyToHashedRSAKey;

mapping(bytes32 => bool) internal _usedSignatures;

function __Registration_init(
uint256 treeHeight_,
address verifier_,
Expand All @@ -37,7 +42,6 @@ contract Registration is PoseidonSMT, Initializable {
bytes memory s_,
bytes memory n_,
VerifierHelper.ProofPoints memory zkPoints_,
uint256 proofTimestamp_,
uint256 group1Hash_
) external {
bytes memory challenge_ = new bytes(8);
Expand All @@ -46,39 +50,44 @@ contract Registration is PoseidonSMT, Initializable {
[uint256(userInternalPublicKeyX_), uint256(userInternalPublicKeyY_)]
);
uint256 hashedRSAKey_ = PoseidonUnit5L.poseidon(_decomposeRSAKey(n_));
uint256 parsedProofTimestamp_ = _parseTimestamp(proofTimestamp_);

for (uint256 i = 0; i < challenge_.length; ++i) {
challenge_[i] = bytes1(uint8(hashedInternalKey_ >> (8 * i)));
}

bytes32 sigHash_ = keccak256(s_);

require(!_usedSignatures[sigHash_], "Registration: signature used");
require(
hashedRSAKeyToInternalKey[bytes32(hashedRSAKey_)] == bytes32(0),
"Registration: passport already registered"
);
require(
internalKeyToHashedRSAKey[bytes32(hashedInternalKey_)] == bytes32(0),
"Registration: identity already registered"
);
require(
challenge_.verifyPassport(s_, abi.encodePacked(E), n_),
"Registration: invalid passport signature"
);

uint256[] memory pubSignals_ = new uint256[](4);

pubSignals_[0] = hashedRSAKey_;
pubSignals_[1] = uint256(icaoMasterTreeMerkleRoot);
pubSignals_[2] = proofTimestamp_;
pubSignals_[3] = group1Hash_;
pubSignals_[0] = hashedRSAKey_; // output
pubSignals_[1] = group1Hash_; // output
pubSignals_[2] = uint256(icaoMasterTreeMerkleRoot); // public input
pubSignals_[3] = hashedInternalKey_; // public input

require(parsedProofTimestamp_ > block.timestamp - 1 days, "Registration: proof expired");
require(verifier.verifyProof(pubSignals_, zkPoints_), "Registration: invalid zk proof");

_add(
bytes32(PoseidonUnit2L.poseidon([hashedRSAKey_, hashedInternalKey_])),
bytes32(group1Hash_)
);
}
uint256 index_ = PoseidonUnit2L.poseidon([hashedRSAKey_, hashedInternalKey_]);

_usedSignatures[sigHash_] = true;

function _parseTimestamp(uint256 proofTimestamp_) private pure returns (uint256) {
uint256 year_ = 2000 + ((proofTimestamp_ >> 16) & 255);
uint256 month_ = (proofTimestamp_ >> 8) & 255;
uint256 day_ = proofTimestamp_ & 255;
hashedRSAKeyToInternalKey[bytes32(hashedRSAKey_)] = bytes32(hashedInternalKey_);
internalKeyToHashedRSAKey[bytes32(hashedInternalKey_)] = bytes32(hashedRSAKey_);

return Date2Time.timestampFromDate(year_, month_, day_);
_add(bytes32(index_), bytes32(PoseidonUnit2L.poseidon([index_, group1Hash_])));
}

function _decomposeRSAKey(
Expand Down
189 changes: 189 additions & 0 deletions contracts/verifiers/RegistrationVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-3.0
/*
Copyright 2021 0KIMS association.
This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity >=0.7.0 <0.9.0;

contract RegistrationVerifier {
// Scalar field size
uint256 constant r =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
// Base field size
uint256 constant q =
21888242871839275222246405745257275088696311157297823662689037894645226208583;

// Verification Key data
uint256 constant alphax =
20491192805390485299153009773594534940189261866228447918068658471970481763042;
uint256 constant alphay =
9383485363053290200918347156157836566562967994039712273449902621266178545958;
uint256 constant betax1 =
4252822878758300859123897981450591353533073413197771768651442665752259397132;
uint256 constant betax2 =
6375614351688725206403948262868962793625744043794305715222011528459656738731;
uint256 constant betay1 =
21847035105528745403288232691147584728191162732299865338377159692350059136679;
uint256 constant betay2 =
10505242626370262277552901082094356697409835680220590971873171140371331206856;
uint256 constant gammax1 =
11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 constant gammax2 =
10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant gammay1 =
4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint256 constant gammay2 =
8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant deltax1 =
3448707029436417451489466772562559293666558416405996711321202817415129272979;
uint256 constant deltax2 =
8740840538261863628665032923013310228587323015866175800935912086948320321467;
uint256 constant deltay1 =
15644319434280961766154094807679524056451785013800067049477473543466823567021;
uint256 constant deltay2 =
11003629941070727077676955103757033892505571960723881292576360191113036222060;

uint256 constant IC0x =
15187141400156529864388393522243026021381866839334417572346308760390025111578;
uint256 constant IC0y =
4911068591892989014406520329884196340710797166381906486252654522059681327190;

uint256 constant IC1x =
20594648766145363376314476034436833347953590221321958598015349163156894946319;
uint256 constant IC1y =
21362709626465521508167630991426194857796473120728709149439940410039314279923;

// Memory data
uint16 constant pVk = 0;
uint16 constant pPairing = 128;

uint16 constant pLastMem = 896;

function verifyProof(
uint[2] calldata _pA,
uint[2][2] calldata _pB,
uint[2] calldata _pC,
uint[1] calldata _pubSignals
) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
}

// G1 function to multiply a G1 value(x,y) to value in an address
function g1_mulAccC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn, 32), y)
mstore(add(mIn, 64), s)

success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)

if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}

mstore(add(mIn, 64), mload(pR))
mstore(add(mIn, 96), mload(add(pR, 32)))

success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)

if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}
}

function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
let _pPairing := add(pMem, pPairing)
let _pVk := add(pMem, pVk)

mstore(_pVk, IC0x)
mstore(add(_pVk, 32), IC0y)

// Compute the linear combination vk_x

g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))

// -A
mstore(_pPairing, calldataload(pA))
mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))

// B
mstore(add(_pPairing, 64), calldataload(pB))
mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
mstore(add(_pPairing, 160), calldataload(add(pB, 96)))

// alpha1
mstore(add(_pPairing, 192), alphax)
mstore(add(_pPairing, 224), alphay)

// beta2
mstore(add(_pPairing, 256), betax1)
mstore(add(_pPairing, 288), betax2)
mstore(add(_pPairing, 320), betay1)
mstore(add(_pPairing, 352), betay2)

// vk_x
mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))

// gamma2
mstore(add(_pPairing, 448), gammax1)
mstore(add(_pPairing, 480), gammax2)
mstore(add(_pPairing, 512), gammay1)
mstore(add(_pPairing, 544), gammay2)

// C
mstore(add(_pPairing, 576), calldataload(pC))
mstore(add(_pPairing, 608), calldataload(add(pC, 32)))

// delta2
mstore(add(_pPairing, 640), deltax1)
mstore(add(_pPairing, 672), deltax2)
mstore(add(_pPairing, 704), deltay1)
mstore(add(_pPairing, 736), deltay2)

let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)

isOk := and(success, mload(_pPairing))
}

let pMem := mload(0x40)
mstore(0x40, add(pMem, pLastMem))

// Validate that all evaluations ∈ F

checkField(calldataload(add(_pubSignals, 0)))

checkField(calldataload(add(_pubSignals, 32)))

// Validate all evaluations
let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)

mstore(0, isValid)
return(0, 0x20)
}
}
}
16 changes: 9 additions & 7 deletions deploy/1_setup.migration.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { ethers } from "hardhat";
import { Deployer, Reporter } from "@solarity/hardhat-migrate";
import { deployPoseidons } from "./helper";
import { deployPoseidons } from "./helpers/helper";

import { Registration__factory, VerifierMock__factory } from "@ethers-v6";
import { Registration__factory, RegistrationVerifier__factory } from "@ethers-v6";

const treeHeight = 80;
const icaoMasterTreeMerkleRoot = ethers.hexlify(
"20044536444086118591887109164436364136320990398424186763077840515405091245125",
);

export = async (deployer: Deployer) => {
await deployPoseidons(
Expand All @@ -11,12 +16,9 @@ export = async (deployer: Deployer) => {
);

const registration = await deployer.deploy(Registration__factory);
const registrationVerifier = await deployer.deploy(RegistrationVerifier__factory);

const verifierMock = await deployer.deploy(VerifierMock__factory);

const icaoMasterTreeMerkleRoot = ethers.hexlify(ethers.randomBytes(32));

await registration.__Registration_init(80, await verifierMock.getAddress(), icaoMasterTreeMerkleRoot);
await registration.__Registration_init(treeHeight, await registrationVerifier.getAddress(), icaoMasterTreeMerkleRoot);

Reporter.reportContracts(["Registration", `${await registration.getAddress()}`]);
};
File renamed without changes.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"description": "Decentralized Identity Issuance",
"scripts": {
"prepare": "husky",
"compile": "npx hardhat compile",
"compile": "npx hardhat compile --force",
"coverage": "npx hardhat coverage --solcoverjs ./.solcover.ts",
"clean": "npx hardhat clean",
"test": "npx hardhat test",
Expand Down
13 changes: 1 addition & 12 deletions test/registration/Registration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,6 @@ describe("Registration", () => {
afterEach(reverter.revert);

describe("#register", () => {
function packDate(timestamp: number) {
const date = new Date(timestamp * 1000);

const year = date.getFullYear();
const month = date.getMonth();
const day = date.getDate();

return day | ((month + 1) << 8) | ((year - 2000) << 16);
}

it("should register", async () => {
const privKey = "0xed54a648103a338f9f9873534951457d99020e6a070c0a565cb0b6308485b577";
const pubKeyX = "0x2c2b7d910cfc889cb631308bfa413b3e784693566068dd94d160521f4c4ee70a";
Expand All @@ -71,9 +61,8 @@ describe("Registration", () => {
],
c: [0, 0],
};
const proofTime = await time.latest();

await registration.register(pubKeyX, pubKeyY, signature, modulus, formattedProof, packDate(proofTime), pubKeyX);
await registration.register(pubKeyX, pubKeyY, signature, modulus, formattedProof, pubKeyX);
});
});
});

0 comments on commit 53fd6ab

Please sign in to comment.