diff --git a/CCTF_Solutions_main/ctf.sol b/CCTF_Solutions_main/ctf.sol new file mode 100644 index 0000000..da30050 --- /dev/null +++ b/CCTF_Solutions_main/ctf.sol @@ -0,0 +1,154 @@ +/** + *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 volStart; + uint256 public volMaxPoints; + uint256 public powDiff; + 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); + + constructor(uint256 _volMaxPoints, uint256 _powDiff) { + admin = msg.sender; + volMaxPoints = _volMaxPoints; + powDiff = _powDiff; + started = false; + } + + function setAdmin(address _admin) external onlyAdmin { + require(_admin != address(0)); + admin = _admin; + } + + function setCCTFStatus(bool _started) external onlyAdmin { + started = _started; + } + + 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); + } + + function setPowDiff(uint256 _powDiff) external onlyAdmin { + powDiff = _powDiff; + } + + + function register(string memory _RTFM) external { + require(players[msg.sender].status == PlayerStatus.Unverified, 'Already registered or banned'); + //uint256 pow = uint256(keccak256(abi.encodePacked("CCTF", msg.sender,"registration", nonce))); + //require(pow < powDiff, "invalid pow"); + require(keccak256(abi.encodePacked('I_read_it')) == keccak256(abi.encodePacked(_RTFM))); // PoW can be used for harder challenges, this is Entry! + players[msg.sender].status = PlayerStatus.Verified; + } + + function setPlayerStatus(address player, PlayerStatus status) external onlyAdmin { + players[player].status = status; + } + + + ////////// Submit flags + mapping(bytes32 => bool) usedNs; // Against replay attack (we only check message signer) + 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"); + + uint[13] memory inputs; + for(uint i =0 ; i < 8;++i){ + inputs[i] = flags[_submitFor].flagHash.value[i]; + } + uint32[5] memory addr = addressToUint32(msg.sender); + for(uint i =0; i < 5;++i){ + inputs[8+i] = addr[i]; + } + bool valid = verifyTx(p,inputs); + assert(valid); + + + 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); + } + + + function addressToUint32 (address _addr) public view 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]; + } +} \ No newline at end of file