Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriianChestnykh committed Nov 5, 2024
1 parent 64284ff commit 66fe34e
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 3 deletions.
6 changes: 6 additions & 0 deletions contracts/interfaces/IZKPVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ interface IZKPVerifier {
bytes data;
}

struct ZKPResponseV3 {
uint256 requestId;
bytes zkProof;
bytes data;
}

/**
* @dev Submit the groth16 proof π=([πa]1,[πb]2,[πc]1) for the ZKP request requestId.
* @param requestId Request id of the ZKP request.
Expand Down
52 changes: 52 additions & 0 deletions contracts/lib/VerifierLibReqType1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;

import {ZKPVerifierBase} from "../verifiers/ZKPVerifierBase.sol";
import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";

/**
* @title VerifierLib
* @dev A library for writing proof results.
*/
library VerifierLibReqType1 {
function writeProofResults(
ZKPVerifierBase.ZKPVerifierStorageProofType1 storage self,
address sender,
uint256 requestId,
ICircuitValidator.Signal[] memory signals
) public {

// TODO COMPLETE THE METHOD IMPLEMENTATION

ZKPVerifierBase.ProofReqType1[] storage proofs = self._proofs[sender][requestId];

uint256 issuerId;
for (uint256 i = 0; i < signals.length; i++) {
if (signals[i].name == "issuerId") {
issuerId = signals[i].value;
}
}
require(issuerId != 0, "Issuer ID not found in the signals");

// TODO research if pushing elements with mapping would work here
// without throwing exceptions in compilator
proofs.push(ProofReqType1{
isVerified: true,
validatorVersion: self._requests[requestId].validator.version(),
blockTimestamp: block.timestamp
});

ZKPVerifierBase.ProofReqType1 storage proof = proofs[proofs.length - 1];

for (uint256 i = 0; i < signals.length; i++) {
proof.storageFields[signals[i].name] = signals[i].value;
if (signals[i].name == "issuerId") {
issuerId = signals[i].value;
}
}

// TODO need to incapusulate this in a function maybe
// as we dong user proofs.length - 1 to avoid 1 proof position ambiguity
self._indexInProofs[sender][requestId][issuerId] = proofs.length;
}
}
5 changes: 5 additions & 0 deletions contracts/verifiers/UniversalVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ contract UniversalVerifier is

/// @dev Event emitted upon submitting a ZKP request
event ZKPResponseSubmitted(uint64 indexed requestId, address indexed caller);
event ZKPResponseSubmittedReqType1(uint256 indexed requestId, address indexed caller, uint256 indexed issuerID);

/// @dev Event emitted upon adding a ZKP request
event ZKPRequestSet(
Expand Down Expand Up @@ -65,6 +66,9 @@ contract UniversalVerifier is
) public override(RequestOwnership, ValidatorWhitelist, ZKPVerifierBase) {
super.setZKPRequest(requestId, request);

//TODO should we define a separate event for RequestType1?
//or we can just decode issuer offchain?
//at least we need to upgrade requestId param in the event uint64 -> uint256
emit ZKPRequestSet(
requestId,
_msgSender(),
Expand Down Expand Up @@ -102,6 +106,7 @@ contract UniversalVerifier is
bytes memory crossChainProof
) public override {
super.submitZKPResponseV2(responses, crossChainProof);
// TODO emit specific event depending the RequestType
for (uint256 i = 0; i < responses.length; i++) {
emit ZKPResponseSubmitted(responses[i].requestId, _msgSender());
}
Expand Down
117 changes: 114 additions & 3 deletions contracts/verifiers/ZKPVerifierBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,122 @@ abstract contract ZKPVerifierBase is IZKPVerifier, ContextUpgradeable {

/// @custom:storage-location erc7201:iden3.storage.ZKPVerifier
struct ZKPVerifierStorage {
mapping(address user => mapping(uint64 requestId => Proof)) _proofs;
mapping(uint64 requestId => IZKPVerifier.ZKPRequest) _requests;
uint64[] _requestIds;
// This group of field is gor RequestType=0 processing
mapping(address user => mapping(uint256 requestId => Proof)) _proofs;
// TODO research if changing from uint64 to uint256 would not break storage location
mapping(uint256 requestId => IZKPVerifier.ZKPRequest) _requests;
// TODO not forget to migrate from uint64[] to uint256[] in the contract upgrade tx
uint256[] _requestIds;
IState _state;
}

/// @custom:storage-location erc7201:iden3.storage.ZKPVerifier.ProofType1
struct ZKPVerifierStorageProofType1 {
// This group of field is gor RequestType=1 processing
// RequestType=1 has a feature of issuer filtering
mapping(address user => mapping(uint256 requestId => ProofReqType1[])) _proofs;
// We should increase the index by 1 when writing to the mapping
// This is to avoid unimbiguous with 0 proof position in the _proof array
mapping(address user => mapping(uint256 requestId => mapping(uint256 issuerId => uint256 _indexInProofs))) _proofsByIssuers;
}

struct ProofReqType1 {
bool isVerified;
mapping(string key => uint256 inputValue) storageFields;
string validatorVersion;
uint256 blockTimestamp;
mapping(string key => bytes) metadata;
}

// 32 bytes (in Big Endian): 31-0x00(not used), 30-0x01(requestType), 29..8-0x00(not used), 7..0 requestId
function setZKPRequestV3(
uint256 requestId,
IZKPVerifier.ZKPRequest calldata request
) public virtual checkRequestExistence(requestId, false) {
// TODO create the isEligibleRequestType method
require(hasEligibleRequestType(requestId), "RequestType not supported");

ZKPVerifierStorage storage s = _getZKPVerifierStorage();
s._requests[requestId] = request;
s._requestIds.push(requestId);
}

function getProofStatusV3(
address sender,
uint256 requestId,
bytes filterData,
) public view checkRequestExistence(requestId, true) returns (IZKPVerifier.ProofStatus memory) {
uint8 requestType = _getRequestType(requestId);

if (requestType == 0) {
require(filterData.length == 0, "FilterData not supported for RequestType=0");
Proof storage proof = _getZKPVerifierStorage()._proofs[sender][requestId];
return
IZKPVerifier.ProofStatus(
proof.isVerified,
proof.validatorVersion,
proof.blockNumber,
proof.blockTimestamp
);
} else if (requestType == 1) {
uint256 issuerId = abi.decode(filterData, (uint256));
require(issuerId != 0, "Issuer ID parameter required for RequestType=1");

// TODO complete by getting the the index first and then getting the proof from the mapping (incapsulate something maybe)
ProofReqType1 storage proof = _getZKPVerifierStorageProofType1()._proofs[sender][requestId][issuerId];

return
IZKPVerifier.ProofStatus(
proof.isVerified,
proof.validatorVersion,
0,
proof.blockTimestamp
);
} else {
revert("RequestType not supported");
}
}

function submitZKPResponseV3(
IZKPVerifier.ZKPResponseV3[] memory responses,
bytes memory crossChainProofs
) {
for (uint256 i = 0; i < responses.length; i++) {
IZKPVerifier.ZKPResponseV3 memory response = responses[i];

address sender = _msgSender();

uint8 requestType = _getRequestType(response.requestId);
IZKPVerifier.ZKPRequest memory request = _getZKPVerifierStorage()._requests[response.requestId];

if (requestType == 0) {
ICircuitValidator.Signal[] memory signals = request.validator.verifyV2(
response.zkProof,
request.data,
sender,
_getZKPVerifierStorage()._state
);

_getZKPVerifierStorage().writeProofResultsV2(sender, response.requestId, signals);
} else if (requestType == 1) {
ICircuitValidator.Signal[] memory signals = request.validator.verifyV2(
response.zkProof,
request.data,
sender,
_getZKPVerifierStorage()._state
);

_getZKPVerifierStorageProofType1().writeProofResults(sender, response.requestId, signals);
} else {
revert("RequestType not supported");
}

if (response.data.length > 0) {
revert("Metadata not supported yet");
}
}
}

// keccak256(abi.encode(uint256(keccak256("iden3.storage.ZKPVerifier")) - 1)) & ~bytes32(uint256(0xff));
bytes32 internal constant ZKPVerifierStorageLocation =
0x512d18c55869273fec77e70d8a8586e3fb133e90f1db24c6bcf4ff3506ef6a00;
Expand All @@ -48,6 +158,7 @@ abstract contract ZKPVerifierBase is IZKPVerifier, ContextUpgradeable {
}

using VerifierLib for ZKPVerifierStorage;
using VerifierLibReqType1 for ZKPVerifierStorageProofType1;

function __ZKPVerifierBase_init(IState state) internal onlyInitializing {
__ZKPVerifierBase_init_unchained(state);
Expand Down

0 comments on commit 66fe34e

Please sign in to comment.