Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

events and data structures #14

Merged
merged 3 commits into from
Apr 12, 2024
Merged
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
2 changes: 1 addition & 1 deletion contracts/IPseudoRand.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface IPseudoRand {
}

struct PartialEval {
uint32 index;
uint32 indexPlus;
Pairing.G1Point value;
IPseudoRand.PartialEvalProof proof;
}
Expand Down
69 changes: 54 additions & 15 deletions contracts/zkdvrf.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ contract zkdvrf is Ownable {
using Strings for uint256;
using Grumpkin for *;

event RegistrationCompleted(uint32 count);
event NidkgStarted();
event NidkgCompleted(uint32 count);
event GlobalPublicParamsCreated();
event RandomInitiated(uint roundNum, string input);
event RandomThresholdReached(uint roundNum, string input);
event RandomReady(uint roundNum, string input);

struct dvrfNode {
address nodeAddress;
bool status;
uint256 deposit;
bool statusPP;
uint32 ppIndex;
uint32 pkIndex;
}

enum Status {
Expand All @@ -41,11 +49,14 @@ contract zkdvrf is Ownable {
uint256 public currentRoundNum;
uint256 public minNodeDeposit;

uint32 public pkListIndex;
Grumpkin.Point[] public pkList;
address[] public pkListOrder;
souradeep-das marked this conversation as resolved.
Show resolved Hide resolved

uint256[][] public ppList;
// vk list order is also same as the ppList
uint32 public ppListIndex;
address[] public ppListOrder;

// The order in vkList is the same as pkList
Pairing.G1Point[] public vkList;
Pairing.G2Point internal gpkVal;

Expand All @@ -59,7 +70,7 @@ contract zkdvrf is Ownable {
mapping (address => dvrfNode) public addrToNode;
mapping (uint256 => string) public roundInput;
mapping (address => uint256) public lastSubmittedRound;
mapping (uint256 => mapping (uint32 => IPseudoRand.PartialEval)) public roundToEval;
mapping (uint256 => IPseudoRand.PartialEval[]) public roundToEval;
mapping (uint256 => uint32) public roundSubmissionCount;
mapping (uint256 => IPseudoRand.PseudoRandom) public roundToRandom;

Expand All @@ -73,7 +84,6 @@ contract zkdvrf is Ownable {
globalPublicParams = globalPublicParamsAddress;
pseudoRand = pseudoRandAddress;
minNodeDeposit = minDeposit;
ppList = new uint256[][](memberCount);
}


Expand All @@ -90,6 +100,7 @@ contract zkdvrf is Ownable {

// each node registers with deposit and confirms
function registerNode(Grumpkin.Point memory pubKey) public payable {
require(registeredCount < currentIndex, "All the permitted nodes have registered so far. Please try again later");
require(contractPhase == Status.Unregistered, "Registration has already been completed");
require(msg.sender == addrToNode[msg.sender].nodeAddress, "Unauthorized call");
require(!addrToNode[msg.sender].status, "Node Already registered");
Expand All @@ -99,12 +110,17 @@ contract zkdvrf is Ownable {
nodes[registeredCount] = msg.sender;
addrToNode[msg.sender].deposit = msg.value;
addrToNode[msg.sender].status = true;
addrToNode[msg.sender].ppIndex = ppListIndex;
addrToNode[msg.sender].pkIndex = pkListIndex;
pkList.push(pubKey);
// ppListOrder is unutilized but added for public visibility
ppListOrder.push(msg.sender);
ppListIndex++;
// pkListOrder is unutilized but added for public visibility
pkListOrder.push(msg.sender);
pkListIndex++;
registeredCount++;

// all the permitted nodes have registered
if (registeredCount == memberCount) {
emit RegistrationCompleted(registeredCount);
}
}

// owner Start Phase 1
Expand All @@ -114,6 +130,8 @@ contract zkdvrf is Ownable {
require(contractPhase == Status.Unregistered, "NIDKG has already been completed");
require(registeredCount == memberCount, "Not all Members are ready");
contractPhase = Status.Nidkg;

emit NidkgStarted();
}

// each node can submit pp_i, zk_i
Expand All @@ -127,12 +145,14 @@ contract zkdvrf is Ownable {

addrToNode[msg.sender].statusPP = true;

uint32 nodeIndex = addrToNode[msg.sender].ppIndex;
ppList[nodeIndex] = pp;
ppList.push(pp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but this assumes - actors will submit public params in the same order that their pk is registered on the contract?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from conversations - pp order is irrelevant to further generation of global public params

// ppListOrder is unutilized but added for public visibility
ppListOrder.push(msg.sender);
ppSubmissionCount++;

if (ppSubmissionCount == memberCount) {
contractPhase = Status.NidkgComplete;
emit NidkgCompleted(ppSubmissionCount);
}
}

Expand All @@ -145,6 +165,8 @@ contract zkdvrf is Ownable {
}
gpkVal = gpkRet;
contractPhase = Status.Ready;

emit GlobalPublicParamsCreated();
}

// 2nd Phase
Expand All @@ -158,6 +180,8 @@ contract zkdvrf is Ownable {
currentRoundNum++;
uint256 currentTimestamp = block.timestamp;
roundInput[currentRoundNum] = currentTimestamp.toString();

emit RandomInitiated(currentRoundNum, roundInput[currentRoundNum]);
}

function submitPartialEval(IPseudoRand.PartialEval memory pEval) public {
Expand All @@ -167,13 +191,17 @@ contract zkdvrf is Ownable {
// this will help revert calls if the contract status is not Ready and the first initiateRandom() is not called
require (lastSubmittedRound[msg.sender] < currentRoundNum, "Already submitted for round");
bytes memory currentX = bytes(roundInput[currentRoundNum]);
uint32 ppIndex = addrToNode[msg.sender].ppIndex;
require(pEval.index == ppIndex + 1);
Pairing.G1Point memory vkStored = vkList[ppIndex];
uint32 pkIndex = addrToNode[msg.sender].pkIndex;
require(pEval.indexPlus == pkIndex + 1);
Pairing.G1Point memory vkStored = vkList[pkIndex];
require(IPseudoRand(pseudoRand).verifyPartialEval(currentX, pEval.value, pEval.proof, vkStored), "Verification of partial eval failed");
lastSubmittedRound[msg.sender] = currentRoundNum;
roundToEval[currentRoundNum][ppIndex] = pEval;
roundToEval[currentRoundNum].push(pEval);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapping is more efficient than arrays, in terms of costs and also protects from a lot of bugs. Given these values are bulky I would be inclined towards map over arrays

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the partial evals need to be downloaded from the contract in order to generate final pseudorandom offchain. I found array easier for retrieving everything and then convert them to be the format that is required in rust (see line 147 in admin.ts). Beside pEval already has index inside the data structure and it doesn't need additional ppIndex. But i am open if you have better way of doing it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally accessing shouldn't be a lot different. But there might be ways to simplify at least some parts given the pp/pk changes. will take a look

roundSubmissionCount[currentRoundNum]++;

if (roundSubmissionCount[currentRoundNum] == threshold) {
emit RandomThresholdReached(currentRoundNum, roundInput[currentRoundNum]);
}
}

// accept a set of partial evals
Expand All @@ -186,6 +214,8 @@ contract zkdvrf is Ownable {
bytes32 value = keccak256(abi.encodePacked(pseudo.proof.x, pseudo.proof.y));
require(pseudo.value == value, "Incorrect pseudorandom value");
roundToRandom[currentRoundNum] = pseudo;

emit RandomReady(currentRoundNum, roundInput[currentRoundNum]);
}

function getLatestRandom() public view returns (IPseudoRand.PseudoRandom memory pseudo) {
Expand Down Expand Up @@ -230,6 +260,11 @@ contract zkdvrf is Ownable {
return true;
}

function getIndexPlus(address nodeAdress) public view returns (uint32) {
uint32 pkIndex = addrToNode[nodeAdress].pkIndex;
return pkIndex + 1;
}

function getPkList() public view returns (Grumpkin.Point[] memory) {
return pkList;
}
Expand All @@ -245,4 +280,8 @@ contract zkdvrf is Ownable {
function getVkList() public view returns (Pairing.G1Point[] memory) {
return vkList;
}

function getEvalList(uint roundNum) public view returns (IPseudoRand.PartialEval[] memory) {
return roundToEval[roundNum];
}
}
17 changes: 17 additions & 0 deletions demo-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"zkdvrfAddress": "0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF",
"memberAddresses": [
"0x85A6bCc74CB8570BEfF8526aec7d0Dfb6F128A60",
"0x7D9e5627B650650Fa3E848364Cb5B0b696B885f2",
"0xec21Cc95d30cc414922292790Bf2E9063bCEe94b",
"0xE7a9aB7B20EFE5B450d7AcB5ABe169166a26DfAC",
"0x5dbfFf2666C351b226cdCe7c1F82B9b0CEbb0bb9"
],
"memberKeys": [
"0x2e978a5709ac0dc3cbc2260519f8fcf5542af54dfaff489bcb4a69182be49429",
"0xa0a98d2341d78ed222b7a6314c026d8e85185203fd295f67b7146be956a05c58",
"0x742e271d909d026b2b4dcc0384ec0b8df8f674f0773c354b57c24858419e89d3",
"0xeeb82181766c7d0fe45d2cb5b3399b1da17a1a432938ec8c4d73daca85eedaea",
"0x88b68d7e8d96d8465cfe3dc4abf707e21aa49139189a784e2d50cc9ada9076c3"
]
}
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
},
"scripts": {
"test": "npx hardhat test",
"deploy": "npx hardhat run scripts/deploy.ts"
"deploy": "npx hardhat run scripts/deploy.ts",
"admin": "npx hardhat run scripts/admin.ts",
"register": "npx hardhat run scripts/register.ts",
"nidkg": "npx hardhat run scripts/nidkg.ts",
"random": "npx hardhat run scripts/random.ts"
},
"repository": {
"type": "git",
Expand Down
Loading
Loading