diff --git a/contracts/CCTF_2023.sol b/contracts/CCTF_2023.sol index b3f5eb1..8b83075 100644 --- a/contracts/CCTF_2023.sol +++ b/contracts/CCTF_2023.sol @@ -37,7 +37,7 @@ contract CryptoCTFX { } struct Challenge { - address obscuredFlag; // essentially the public key of the flag, the flag being a private key + address obscuredFlag; // Essentially the public key of the flag, the flag being a private key uint worth; uint256 descriptionFingerprint; bool onlyFirstSolver; @@ -59,26 +59,38 @@ contract CryptoCTFX { event ChallengeAddedOrUpdated(uint contestID, uint indexed challengeID); event ChallengeSolved(uint contestID, uint indexed challengeID, address indexed solver); + /* CTF Manager functions */ + + // 1. Create a contest function createContest(uint contestID, string memory password) external { require(contests[contestID].admin == address(0), "This contest ID has already been registered"); contests[contestID].admin = msg.sender; contests[contestID].password = password; } + // 2. Set the contest's deadline + function setContestDeadline(uint contestID, uint256 deadline) external onlyExistingContest(contestID) onlyAdmin(contestID) { + contests[contestID].deadline = deadline; + } + + // 3. Add the public keys of the challenges and their relevant data + function addOrUpdateChallenge(uint contestID, uint challengeID, address obscuredFlag, uint worth, uint256 descriptionFingerprint, bool onlyFirstSolver, string memory skill) external onlyExistingContest(contestID) onlyAdmin(contestID) { + require(obscuredFlag != address(0), "The obscured flag value must not be 0"); + contests[contestID].challenges[challengeID] = Challenge(obscuredFlag, worth, descriptionFingerprint, onlyFirstSolver, skill); + emit ChallengeAddedOrUpdated(contestID, challengeID); + } + + function setPlayerStatus(uint contestID, address player, PlayerStatus status) external onlyExistingContest(contestID) onlyAdmin(contestID) { + contests[contestID].players[player].status = status; + } + function setAdmin(uint contestID, address newAdmin) external onlyExistingContest(contestID) onlyAdmin(contestID) { require(newAdmin != address(0)); contests[contestID].admin = newAdmin; } - function setContestDeadline(uint contestID, uint256 deadline) external onlyExistingContest(contestID) onlyAdmin(contestID) { - contests[contestID].deadline = deadline; - } - function addOrUpdateChallenge(uint contestID, uint challengeID, address obscuredFlag, uint worth, uint256 descriptionFingerprint, bool onlyFirstSolver, string memory skill) external onlyExistingContest(contestID) onlyAdmin(contestID) { - require(obscuredFlag != address(0), "The obscured flag value must not be 0"); - contests[contestID].challenges[challengeID] = Challenge(obscuredFlag, worth, descriptionFingerprint, onlyFirstSolver, skill); - emit ChallengeAddedOrUpdated(contestID, challengeID); - } + /* CTF Player functions */ function register(uint contestID, string memory password) external onlyExistingContest(contestID) { require(contests[contestID].players[msg.sender].status == PlayerStatus.Unverified, "You are already registered or banned in this contest"); @@ -86,10 +98,7 @@ contract CryptoCTFX { contests[contestID].players[msg.sender].status = PlayerStatus.Verified; } - function setPlayerStatus(uint contestID, address player, PlayerStatus status) external onlyExistingContest(contestID) onlyAdmin(contestID) { - contests[contestID].players[player].status = status; - } - + // You can use six's eth_keygen to generate the signature function submitFlag(uint contestID, uint challengeID, bytes memory signature) external onlyExistingContest(contestID) onlyExistingChallenge(contestID, challengeID) onlyOpen(contestID) { require(contests[contestID].players[msg.sender].status == PlayerStatus.Verified, "You are unverified or banned in this contest"); // the correct signature is an ECDSA signature where (1) the message (hash) is the sender address and (2) the private key is the flag; @@ -108,6 +117,7 @@ contract CryptoCTFX { emit ChallengeSolved(contestID, challengeID, msg.sender); } + /* CTF ECDSA related functions */ function recoverSigner(bytes32 messageHash, bytes memory signature) public pure returns (address) { (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature); return ecrecover(messageHash, v, r, s); @@ -122,6 +132,7 @@ contract CryptoCTFX { } } + /* CTF View functions for feedback and FE */ function getContestDeadline(uint contestID) external view onlyExistingContest(contestID) returns (uint256) { return contests[contestID].deadline; } @@ -133,4 +144,4 @@ contract CryptoCTFX { function getPlayerScore(uint contestID, address player) external view onlyExistingContest(contestID) returns (uint) { return contests[contestID].players[player].score; } -} +} \ No newline at end of file