Skip to content

Commit 3a930be

Browse files
committed
refactor: hidden votes verification logic
1 parent 87e5759 commit 3a930be

File tree

3 files changed

+71
-41
lines changed

3 files changed

+71
-41
lines changed

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,13 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
334334
{
335335
(uint96 courtID, , , , ) = core.disputes(_coreDisputeID);
336336
(, bool hiddenVotes, , , , ) = core.courts(courtID);
337-
bytes32 actualVoteHash = hashVote(_choice, _salt, _justification);
337+
if (hiddenVotes) {
338+
_verifyHiddenVoteCommitments(localDisputeID, localRoundID, _voteIDs, _choice, _justification, _salt);
339+
}
338340

339341
// Save the votes.
340342
for (uint256 i = 0; i < _voteIDs.length; i++) {
341343
if (round.votes[_voteIDs[i]].account != _juror) revert JurorHasToOwnTheVote();
342-
if (hiddenVotes && _getExpectedVoteHash(localDisputeID, localRoundID, _voteIDs[i]) != actualVoteHash)
343-
revert HashDoesNotMatchHiddenVoteCommitment();
344-
if (!_checkJustification(localDisputeID, localRoundID, _voteIDs[i], _justification, _salt))
345-
revert WrongJustification();
346344
if (round.votes[_voteIDs[i]].voted) revert VoteAlreadyCast();
347345
round.votes[_voteIDs[i]].choice = _choice;
348346
round.votes[_voteIDs[i]].voted = true;
@@ -713,29 +711,26 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
713711
// * Internal * //
714712
// ************************************* //
715713

716-
/// @notice Returns the expected vote hash for a given vote.
714+
/// @notice Verifies that revealed choice and justification match the hidden vote commitments.
717715
/// @param _localDisputeID The ID of the dispute in the Dispute Kit.
718716
/// @param _localRoundID The ID of the round in the Dispute Kit.
719-
/// @param _voteID The ID of the vote.
720-
/// @return The expected vote hash.
721-
function _getExpectedVoteHash(
717+
/// @param _voteIDs The IDs of the votes.
718+
/// @param _choice The choice.
719+
/// @param _justification The justification.
720+
/// @param _salt The salt.
721+
function _verifyHiddenVoteCommitments(
722722
uint256 _localDisputeID,
723723
uint256 _localRoundID,
724-
uint256 _voteID
725-
) internal view virtual returns (bytes32) {
726-
return disputes[_localDisputeID].rounds[_localRoundID].votes[_voteID].commit;
727-
}
728-
729-
/// @notice Returns true if submitted justification matches. Only used by specific Dispute Kits (eg Shutter).
730-
/// @return Whether justification matches or not.
731-
function _checkJustification(
732-
uint256 /*_localDisputeID*/,
733-
uint256 /*_localRoundID*/,
734-
uint256 /*_voteID*/,
735-
string memory /*_justification*/,
736-
uint256 /*_salt*/
737-
) internal view virtual returns (bool) {
738-
return true;
724+
uint256[] calldata _voteIDs,
725+
uint256 _choice,
726+
string memory _justification,
727+
uint256 _salt
728+
) internal view virtual {
729+
bytes32 actualVoteHash = hashVote(_choice, _salt, _justification);
730+
for (uint256 i = 0; i < _voteIDs.length; i++) {
731+
if (disputes[_localDisputeID].rounds[_localRoundID].votes[i].commit != actualVoteHash)
732+
revert HashDoesNotMatchHiddenVoteCommitment();
733+
}
739734
}
740735

741736
/// @notice Checks that the chosen address satisfies certain conditions for being drawn.
@@ -785,5 +780,4 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
785780
error AppealFeeIsAlreadyPaid();
786781
error DisputeNotResolved();
787782
error CoreIsPaused();
788-
error WrongJustification();
789783
}

contracts/src/arbitration/dispute-kits/DisputeKitGatedShutter.sol

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,23 +165,40 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
165165
callerIsJuror = false;
166166
}
167167

168+
// ************************************* //
169+
// * Public Views * //
170+
// ************************************* //
171+
172+
/// @notice Computes the hash of a justification using ABI encoding
173+
/// @param _salt A random salt for commitment
174+
/// @param _justification The justification for the vote
175+
/// @return bytes32 The hash of the encoded justification
176+
function hashJustification(uint256 _salt, string memory _justification) public pure returns (bytes32) {
177+
return keccak256(abi.encode(_salt, keccak256(bytes(_justification))));
178+
}
179+
168180
// ************************************* //
169181
// * Internal * //
170182
// ************************************* //
171183

172184
/// @inheritdoc DisputeKitClassicBase
173-
function _checkJustification(
185+
function _verifyHiddenVoteCommitments(
174186
uint256 _localDisputeID,
175187
uint256 _localRoundID,
176-
uint256 _voteID,
188+
uint256[] calldata _voteIDs,
189+
uint256 _choice,
177190
string memory _justification,
178191
uint256 _salt
179-
) internal view override returns (bool) {
180-
if (!callerIsJuror) {
181-
bytes32 justificationCommit = justificationCommitments[_localDisputeID][_localRoundID][_voteID];
182-
return justificationCommit == keccak256(abi.encode(_salt, keccak256(bytes(_justification))));
183-
} else {
184-
return true;
192+
) internal view override {
193+
super._verifyHiddenVoteCommitments(_localDisputeID, _localRoundID, _voteIDs, _choice, _justification, _salt);
194+
195+
// The juror is allowed to reveal without verifying the justification commitment for recovery purposes.
196+
if (callerIsJuror) return;
197+
198+
bytes32 actualJustificationHash = hashJustification(_salt, _justification);
199+
for (uint256 i = 0; i < _voteIDs.length; i++) {
200+
if (justificationCommitments[_localDisputeID][_localRoundID][_voteIDs[i]] != actualJustificationHash)
201+
revert WrongJustification();
185202
}
186203
}
187204

@@ -241,4 +258,5 @@ contract DisputeKitGatedShutter is DisputeKitClassicBase {
241258
// ************************************* //
242259

243260
error EmptyJustificationCommit();
261+
error WrongJustification();
244262
}

contracts/src/arbitration/dispute-kits/DisputeKitShutter.sol

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,40 @@ contract DisputeKitShutter is DisputeKitClassicBase {
149149
callerIsJuror = false;
150150
}
151151

152+
// ************************************* //
153+
// * Public Views * //
154+
// ************************************* //
155+
156+
/// @notice Computes the hash of a justification using ABI encoding
157+
/// @param _salt A random salt for commitment
158+
/// @param _justification The justification for the vote
159+
/// @return bytes32 The hash of the encoded justification
160+
function hashJustification(uint256 _salt, string memory _justification) public pure returns (bytes32) {
161+
return keccak256(abi.encode(_salt, keccak256(bytes(_justification))));
162+
}
163+
152164
// ************************************* //
153165
// * Internal * //
154166
// ************************************* //
155167

156168
/// @inheritdoc DisputeKitClassicBase
157-
function _checkJustification(
169+
function _verifyHiddenVoteCommitments(
158170
uint256 _localDisputeID,
159171
uint256 _localRoundID,
160-
uint256 _voteID,
172+
uint256[] calldata _voteIDs,
173+
uint256 _choice,
161174
string memory _justification,
162175
uint256 _salt
163-
) internal view override returns (bool) {
164-
if (!callerIsJuror) {
165-
bytes32 justificationCommit = justificationCommitments[_localDisputeID][_localRoundID][_voteID];
166-
return justificationCommit == keccak256(abi.encode(_salt, keccak256(bytes(_justification))));
167-
} else {
168-
return true;
176+
) internal view override {
177+
super._verifyHiddenVoteCommitments(_localDisputeID, _localRoundID, _voteIDs, _choice, _justification, _salt);
178+
179+
// The juror is allowed to reveal without verifying the justification commitment for recovery purposes.
180+
if (callerIsJuror) return;
181+
182+
bytes32 actualJustificationHash = hashJustification(_salt, _justification);
183+
for (uint256 i = 0; i < _voteIDs.length; i++) {
184+
if (justificationCommitments[_localDisputeID][_localRoundID][_voteIDs[i]] != actualJustificationHash)
185+
revert WrongJustification();
169186
}
170187
}
171188

@@ -174,4 +191,5 @@ contract DisputeKitShutter is DisputeKitClassicBase {
174191
// ************************************* //
175192

176193
error EmptyJustificationCommit();
194+
error WrongJustification();
177195
}

0 commit comments

Comments
 (0)