Created
December 3, 2024 07:01
-
-
Save voltrevo/fd848c55bb01f425b81847ed6716c051 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: CC0-1.0 | |
pragma solidity ^0.8.0; | |
contract MPCCommitment { | |
address payable public x; | |
address payable public y; | |
uint256 public depositValue; | |
bytes32 public G; | |
bytes32 public hash_rx; | |
bytes32 public hash_ry; | |
mapping(address => bytes32) public revealedR; | |
uint256 public revealBlockNumber; | |
uint256 public revealDeadline; | |
enum State { Created, Committed, Revealing, Completed } | |
State public state; | |
// Constructor: X creates the contract with depositValue, G, keccak(rx), keccak(ry) | |
constructor( | |
uint256 _depositValue, | |
bytes32 _G, | |
bytes32 _hash_rx, | |
bytes32 _hash_ry, | |
address payable _y | |
) payable { | |
require(msg.value == _depositValue, "X must deposit the depositValue"); | |
x = payable(msg.sender); | |
y = _y; | |
depositValue = _depositValue; | |
G = _G; | |
hash_rx = _hash_rx; | |
hash_ry = _hash_ry; | |
state = State.Created; | |
} | |
// X can cancel and withdraw their depositValue before Y commits | |
function cancel() public { | |
require(state == State.Created, "Cannot cancel after commitment"); | |
require(msg.sender == x, "Only X can cancel"); | |
state = State.Completed; | |
x.transfer(address(this).balance); | |
} | |
// Y deposits depositValue and commits | |
function commit() public payable { | |
require(state == State.Created, "Already committed"); | |
require(msg.sender == y, "Only Y can commit"); | |
require(msg.value == depositValue, "Incorrect deposit value"); | |
state = State.Committed; | |
} | |
// X or Y can call forfeit(), which awards the funds to the other party | |
function forfeit() public { | |
require(state == State.Committed || state == State.Revealing, "Cannot forfeit in current state"); | |
require(msg.sender == x || msg.sender == y, "Only X or Y can forfeit"); | |
address payable winner = (msg.sender == x) ? y : x; | |
state = State.Completed; | |
winner.transfer(address(this).balance); | |
} | |
// X or Y can call reveal() with their r value | |
function reveal(bytes32 r) public { | |
require(state == State.Committed || state == State.Revealing, "Cannot reveal in current state"); | |
require(msg.sender == x || msg.sender == y, "Only X or Y can reveal"); | |
require(revealedR[msg.sender] == bytes32(0), "Already revealed"); | |
bytes32 hash_r = keccak256(abi.encodePacked(r)); | |
if (msg.sender == x) { | |
require(hash_r == hash_rx, "Invalid r value for X"); | |
} else { | |
require(hash_r == hash_ry, "Invalid r value for Y"); | |
} | |
revealedR[msg.sender] = r; | |
if (revealBlockNumber == 0) { | |
// First reveal | |
revealBlockNumber = block.number; | |
revealDeadline = block.number + 1000; | |
state = State.Revealing; | |
} | |
if (revealedR[x] != bytes32(0) && revealedR[y] != bytes32(0)) { | |
// Both have revealed | |
settle(); | |
} | |
} | |
// The first revealing party can call claim() after the other fails to reveal in time | |
function claim() public { | |
require(state == State.Revealing, "Claim not allowed in current state"); | |
require(revealedR[msg.sender] != bytes32(0), "You have not revealed your r"); | |
require(block.number >= revealDeadline, "Reveal deadline has not passed"); | |
state = State.Completed; | |
payable(msg.sender).transfer(address(this).balance); | |
} | |
// Internal function to compute f(x,y) and distribute the funds | |
function settle() internal { | |
bytes32 rx = revealedR[x]; | |
bytes32 ry = revealedR[y]; | |
bytes32 fxy_bytes = G ^ rx ^ ry; | |
uint256 fxy = uint256(fxy_bytes); | |
state = State.Completed; | |
if (fxy == 0) { | |
// Award funds to X | |
x.transfer(address(this).balance); | |
} else if (fxy == 1) { | |
// Award funds to Y | |
y.transfer(address(this).balance); | |
} else { | |
// Return funds evenly | |
uint256 balance = address(this).balance; | |
x.transfer(balance / 2); | |
y.transfer(balance / 2); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment