/** *Submitted for verification at polygonscan.com on 2022-08-24 */ // SPDX-License-Identifier: Apache-2.0 // Authors: six and Silur pragma solidity ^0.8.16; import "./verifier.sol"; contract CCTF9 is Verifier { address public admin; uint256 public volMaxPoints; bool public started; enum PlayerStatus { Unverified, Verified, Banned } struct Player { PlayerStatus status; uint256 points; } modifier onlyAdmin() { require(msg.sender == admin, "Not admin"); _; } modifier onlyActive() { require(started == true, "CCTF not started."); _; } struct Hash { uint32[8] value; } struct Flag { Hash flagHash; bool onlyFirstSolver; uint256 points; string skill_name; } mapping(address => Player) public players; mapping(uint256 => Flag) public flags; event CCTFStarted(uint256 timestamp); event FlagAdded(uint256 indexed flagId, Hash flagHash); event FlagRemoved(uint256 indexed flagId); event FlagSolved(uint256 indexed flagId, address indexed solver); event PlayerRegistered(address playerAddress); constructor(uint256 _volMaxPoints) { admin = msg.sender; volMaxPoints = _volMaxPoints; started = false; } /// transfers the admin privilege to _admin address function setAdmin(address _admin) external onlyAdmin { require(_admin != address(0)); admin = _admin; } /// can be used to set the status of the cctf to started or finished function setCCTFStatus(bool _started) external onlyAdmin { started = _started; } /// creates a new capturable flag according to the arguments function setFlag( uint256 _flagId, Hash memory _flagHash, bool _onlyFirstSolver, uint256 _points, string memory _skill ) external onlyAdmin { flags[_flagId] = Flag(_flagHash, _onlyFirstSolver, _points, _skill); emit FlagAdded(_flagId, _flagHash); } /// registers the caller as a player function register() external { require( players[msg.sender].status == PlayerStatus.Unverified, "Already registered or banned" ); players[msg.sender].status = PlayerStatus.Verified; emit PlayerRegistered(msg.sender); } /// sets the player's status either to Unverified, Verified or Banned function setPlayerStatus(address player, PlayerStatus status) external onlyAdmin { players[player].status = status; } ////////// Submit flags mapping(address => mapping(uint256 => bool)) Solves; // address -> challenge ID -> solved/not uint256 public submission_success_count = 0; // For statistics function SubmitFlag(Proof memory p, uint256 _submitFor) external onlyActive { require( players[msg.sender].status == PlayerStatus.Verified, "You are not even playing" ); uint256[13] memory inputs; for (uint256 i = 0; i < 8; ++i) { inputs[i] = flags[_submitFor].flagHash.value[i]; } uint32[5] memory addr = addressToUint32(msg.sender); for (uint256 i = 0; i < 5; ++i) { inputs[8 + i] = addr[i]; } bool valid = verifyTx(p, inputs); require(valid,"The proof is invalid"); require(!Solves[msg.sender][_submitFor],"You cannot submit your solution more than once"); // can't submit the same flag multiple times Solves[msg.sender][_submitFor] = true; players[msg.sender].points += flags[_submitFor].points; players[msg.sender].points = players[msg.sender].points < volMaxPoints ? players[msg.sender].points : volMaxPoints; if (flags[_submitFor].onlyFirstSolver) { flags[_submitFor].points = 0; } submission_success_count = submission_success_count + 1; emit FlagSolved(_submitFor, msg.sender); } /// maps an address to unsigned int function addressToUint32(address _addr) public pure returns (uint32[5] memory) { uint256 targetUint = uint256(uint160(_addr)); uint32[5] memory addr = [ uint32(targetUint / 4294967296**4), uint32(targetUint / 4294967296**3), uint32(targetUint / 4294967296**2), uint32(targetUint / 4294967296), uint32(targetUint) ]; return addr; } ////////// Check status, scores, etc function getPlayerStatus(address _player) external view returns (PlayerStatus) { return players[_player].status; } function getPlayerPoints(address _player) external view returns (uint256) { return players[_player].points < volMaxPoints ? players[_player].points : volMaxPoints; } function getSuccessfulSubmissionCount() external view returns (uint256) { return submission_success_count; } function getFlag(uint256 id) external view returns (Flag memory) { return flags[id]; } }