Skip to content
This repository has been archived by the owner on Mar 3, 2022. It is now read-only.

Commit

Permalink
EthDKG contract upgrades (#10)
Browse files Browse the repository at this point in the history
* Snapshot facet with tests

* Removed commented code

* Add ownerOrOperator modifier for access control

* Added currentEpoch methods to staking for compatibility.

* Removed commented code. Added participants modifier for snapshots.

* Recompiled and generated bindings.

* Restricted facet for diamond maintenance

* Added admin functions to interface

* Added missing majorFine()/minorFine()

* Adding migration contracts/facets

* Moved event definitions

* ETHDKG migrator + test

* Fixed loop index for members

* Switch from a manual call() to a cast

* Added snapshot failure test for bad signature

* Added test for migration of snapshot

* Added staking test case

* Create constant for minimum stake. Added testing for immediately adding/removing validator

* Turned off test tracing and generated bindings

* Put the owner only requirement back

* Regenerated bindings

* Renamed overloaded function deposit() to depositFor()

* Minor style updates to match recommendations

* Feature complete ETHDKG replacement with diamond pattern

* Complete unit tests

* Put missing access controls back

* Finished splitting ETHDKG

* Added restart of ETHDKG if final completion detects issue

* Made validator queueing consistently require staking. Restored snapshot rewards.

* Phase length admin exposed

* Consolidated EthDKG constants into Library. Updated abicoder to v2.

* Removed commented code.

* Renamed utility token

* Brought over TODOs from Chris
  • Loading branch information
anthonygd committed May 20, 2021
1 parent ce1a097 commit c8008fb
Show file tree
Hide file tree
Showing 33 changed files with 3,470 additions and 744 deletions.
3,472 changes: 2,970 additions & 502 deletions bindings/bridge.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/dapp.sol.json

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions src/CryptoLibrary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pragma solidity >=0.5.15;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// TODO: we may want to check some of the functions to ensure that they are valid.
// some of them may not be if there are attempts they are called with
// invalid points.
library CryptoLibrary {

////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -44,8 +47,8 @@ library CryptoLibrary {
// In the future, the specific value of H1 could be changed every time
// there is a change in validator set. For right now, though, this will
// be a fixed constant.
// uint256 constant H1x = 2788159449993757418373833378244720686978228247930022635519861138679785693683;
// uint256 constant H1y = 12344898367754966892037554998108864957174899548424978619954608743682688483244;
uint256 constant H1x = 2788159449993757418373833378244720686978228247930022635519861138679785693683;
uint256 constant H1y = 12344898367754966892037554998108864957174899548424978619954608743682688483244;

// H2 == ([H2xi, H2x], [H2yi, H2y]) is the *negation* of the
// standard generator of group G2.
Expand All @@ -72,6 +75,9 @@ library CryptoLibrary {
uint256 constant H2yi = 17805874995975841540914202342111839520379459829704422454583296818431106115052;
uint256 constant H2y = 13392588948715843804641432497768002650278120570034223513918757245338268106653;

uint256 constant G1x = 1;
uint256 constant G1y = 2;

// two256modP == 2^256 mod FIELD_MODULUS;
// this is used in hashToBase to obtain a more uniform hash value.
uint256 constant two256modP = 6350874878119819312338956282401532409788428879151445726012394534686998597021;
Expand Down Expand Up @@ -133,7 +139,7 @@ library CryptoLibrary {
proof_is_valid = challenge == proof[0];
}


// TODO: identity (0, 0) should be considered a valid point
function bn128_is_on_curve(uint256[2] memory point)
internal pure returns(bool)
{
Expand Down Expand Up @@ -587,6 +593,8 @@ library CryptoLibrary {
// safeSigningPoint ensures that the HashToG1 point we are returning
// is safe to sign; in particular, it is not Infinity (the group identity
// element) or the standard curve generator (curveGen) or its negation.
//
// TODO: may want to confirm point is valid first as well as reducing mod field prime
function safeSigningPoint(uint256[2] memory input)
internal pure returns (bool) {
if (input[0] == 0 || input[0] == 1) {
Expand Down
62 changes: 0 additions & 62 deletions src/EthDKGConstants.sol

This file was deleted.

2 changes: 1 addition & 1 deletion src/facets/DiamondUpdateFacet.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT-open-group
pragma solidity >=0.6.4;
pragma experimental ABIEncoderV2;
pragma abicoder v2;

import "./AccessControlLibrary.sol";
import "./DiamondStorageLibrary.sol";
Expand Down
25 changes: 25 additions & 0 deletions src/facets/EthDKG.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT-open-group
pragma solidity >=0.7.4;

import "ds-test/test.sol";

import "./Setup.t.sol";


contract EthDKG is Constants, DSTest, Setup {

address me = address(this);

function testGetDefaultPhaseLength() public {
ethdkg.initializeEthDKG(registry);
assertEq(ethdkg.getPhaseLength(), 40);
}

function testSetPhaseLength() public {
ethdkg.initializeEthDKG(registry);

ethdkg.updatePhaseLength(4);
assertEq(ethdkg.getPhaseLength(), 4);
}

}
4 changes: 2 additions & 2 deletions src/facets/EthDKGCompletionFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ contract EthDKGCompletionFacet {
}

if (reinitialize) {
EthDKGLibrary.initializeState();
}
EthDKGLibrary.initializeState();
}
}
}
167 changes: 167 additions & 0 deletions src/facets/EthDKGGroupAccusationFacet.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT-open-group
pragma solidity >=0.5.15;
pragma abicoder v2;

import "../CryptoLibrary.sol";
import "./EthDKGLibrary.sol";
Expand Down Expand Up @@ -84,4 +85,170 @@ contract EthDKGGroupAccusationFacet {
}
}
}

// Perform Group accusation by computing gpkj*
//
// gpkj has already been submitted and stored in gpkj_submissions.
// To confirm this is valid, we need to compute gpkj*, the corresponding
// G1 element; we remember gpkj is a public key and an element of G2.
// Once, we compute gpkj*, we can confirm
//
// e(gpkj*, h2) != e(g1, gpkj)
//
// via a pairing check.
// If we have inequality, then the participant is malicious;
// if we have equality, then the accusor is malicious.
function Group_Accusation_GPKj_Comp(
uint256[][] memory encrypted_shares,
uint256[2][][] memory commitments,
uint256 dishonest_list_idx,
address dishonestAddress
)
public
{
EthDKGLibrary.EthDKGStorage storage es = EthDKGLibrary.ethDKGStorage();

require(
(es.T_GPKJ_SUBMISSION_END < block.number) && (block.number <= es.T_GPKJ_DISPUTE_END),
"gpkj acc comp failed: contract is not in gpkj accusation phase"
);

// n is total participants;
// t is threshold, so that t+1 is BFT majority.
uint256 n = es.addresses.length;
uint256 k = n / 3;
uint256 t = 2*k;
if (2 == (n - 3*k)) {
t = t + 1;
}

// Begin initial check
////////////////////////////////////////////////////////////////////////
// First, check length of things
require(
(encrypted_shares.length == n) && (commitments.length == n),
"gpkj acc comp failed: invalid submission of arguments"
);

// Now, ensure subarrays are the correct length as well
for (k = 0; k < n; k++) {
require(
encrypted_shares[k].length == n - 1,
"gpkj acc comp failed: invalid number of encrypted shares provided"
);
require(
commitments[k].length == t + 1,
"gpkj acc comp failed: invalid number of commitments provided"
);
}

// Ensure submissions are valid
for (k = 0; k < n; k++) {
address currentAddr = es.addresses[k];
require(
es.share_distribution_hashes[currentAddr] == keccak256(
abi.encodePacked(encrypted_shares[k], commitments[k])
),
"gpkj acc comp failed: invalid shares or commitments"
);
}

// Confirm nontrivial submission
if ((es.gpkj_submissions[dishonestAddress][0] == 0) &&
(es.gpkj_submissions[dishonestAddress][1] == 0) &&
(es.gpkj_submissions[dishonestAddress][2] == 0) &&
(es.gpkj_submissions[dishonestAddress][3] == 0)) {
return;
}
// ^^^ TODO: this check will need to be changed once we allow for multiple accusations per loop

// Ensure address submissions are correct; this will be converted to loop later
require(
es.addresses[dishonest_list_idx] == dishonestAddress,
"gpkj acc comp failed: dishonest index does not match dishonest address"
);
////////////////////////////////////////////////////////////////////////
// End initial check

// At this point, everything has been validated.
uint256 j = dishonest_list_idx + 1;

// Info for looping computation
uint256 pow;
uint256[2] memory gpkjStar;
uint256[2] memory tmp;
uint256 idx;

// Begin computation loop
//
// We remember
//
// F_i(x) = C_i0 * C_i1^x * C_i2^(x^2) * ... * C_it^(x^t)
// = Prod(C_ik^(x^k), k = 0, 1, ..., t)
//
// We now compute gpkj*. We have
//
// gpkj* = Prod(F_i(j), i)
// = Prod( Prod(C_ik^(j^k), k = 0, 1, ..., t), i)
// = Prod( Prod(C_ik^(j^k), i), k = 0, 1, ..., t) // Switch order
// = Prod( [Prod(C_ik, i)]^(j^k), k = 0, 1, ..., t) // Move exponentiation outside
//
// More explicityly, we have
//
// gpkj* = Prod(C_i0, i) *
// [Prod(C_i1, i)]^j *
// [Prod(C_i2, i)]^(j^2) *
// ...
// [Prod(C_it, i)]^(j^t) *
//
////////////////////////////////////////////////////////////////////////
// Add constant terms
gpkjStar = commitments[0][0]; // Store initial constant term
for (idx = 1; idx < n; idx++) {
gpkjStar = CryptoLibrary.bn128_add([gpkjStar[0], gpkjStar[1], commitments[idx][0][0], commitments[idx][0][1]]);
}

// Add linear term
tmp = commitments[0][1]; // Store initial linear term
pow = j;
for (idx = 1; idx < n; idx++) {
tmp = CryptoLibrary.bn128_add([tmp[0], tmp[1], commitments[idx][1][0], commitments[idx][1][1]]);
}
tmp = CryptoLibrary.bn128_multiply([tmp[0], tmp[1], pow]);
gpkjStar = CryptoLibrary.bn128_add([gpkjStar[0], gpkjStar[1], tmp[0], tmp[1]]);

// Loop through higher order terms
for (k = 2; k <= t; k++) {
tmp = commitments[0][k]; // Store initial degree k term
// Increase pow by factor
pow = mulmod(pow, j, CryptoLibrary.GROUP_ORDER);
//x = mulmod(x, disputer_idx, GROUP_ORDER);
for (idx = 1; idx < n; idx++) {
tmp = CryptoLibrary.bn128_add([tmp[0], tmp[1], commitments[idx][k][0], commitments[idx][k][1]]);
}
tmp = CryptoLibrary.bn128_multiply([tmp[0], tmp[1], pow]);
gpkjStar = CryptoLibrary.bn128_add([gpkjStar[0], gpkjStar[1], tmp[0], tmp[1]]);
}
////////////////////////////////////////////////////////////////////////
// End computation loop

// We now have gpkj*; we now verify.
uint256[4] memory gpkj = es.gpkj_submissions[dishonestAddress];
bool isValid = CryptoLibrary.bn128_check_pairing([
gpkjStar[0], gpkjStar[1],
CryptoLibrary.H2xi, CryptoLibrary.H2x, CryptoLibrary.H2yi, CryptoLibrary.H2y,
CryptoLibrary.G1x, CryptoLibrary.G1y,
gpkj[0], gpkj[1], gpkj[2], gpkj[3]
]);
if (isValid) {
// Valid gpkj submission; burn whomever submitted accusation
delete es.gpkj_submissions[msg.sender];
es.is_malicious[msg.sender] = true;
}
else {
// Invalid gpkj submission; burn participant
delete es.gpkj_submissions[dishonestAddress];
es.is_malicious[dishonestAddress] = true;
}
}
}
7 changes: 5 additions & 2 deletions src/facets/EthDKGInformationFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ pragma solidity >=0.7.4;

import "../Constants.sol";
import "../CryptoLibrary.sol";
import "../EthDKGConstants.sol";
import "../Registry.sol";
import "./EthDKGLibrary.sol";

contract EthDKGInformationFacet is Constants, EthDKGConstants {
contract EthDKGInformationFacet is Constants {

//
// Informational
Expand Down Expand Up @@ -87,4 +86,8 @@ contract EthDKGInformationFacet is Constants, EthDKGConstants {
function commitments_1st_coefficient(address addr, uint256 idx) external view returns (uint256) {
return EthDKGLibrary.ethDKGStorage().commitments_1st_coefficient[addr][idx];
}

function getPhaseLength() external view returns (uint256) {
return EthDKGLibrary.ethDKGStorage().DELTA_INCLUDE;
}
}
5 changes: 5 additions & 0 deletions src/facets/EthDKGInitializeFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ contract EthDKGInitializeFacet is AccessControlled, Constants {
es.DELTA_CONFIRM = 6;
es.MINIMUM_REGISTRATION = 4;
}

function updatePhaseLength(uint256 phaseLength) external onlyOperator {
EthDKGLibrary.ethDKGStorage().DELTA_INCLUDE = phaseLength;
}

}
2 changes: 1 addition & 1 deletion src/facets/EthDKGLibrary.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT-open-group
pragma solidity >=0.7.4;
pragma experimental ABIEncoderV2;
pragma abicoder v2;

import "../interfaces/Validators.sol";

Expand Down
Loading

0 comments on commit c8008fb

Please sign in to comment.