solutions/CCTF_Solutions_main/ctf.sol

146 lines
4.5 KiB
Solidity

/**
*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;
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) {
admin = msg.sender;
volMaxPoints = _volMaxPoints;
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 register(string memory _RTFM) external {
require(players[msg.sender].status == PlayerStatus.Unverified, 'Already registered or banned');
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);
require(valid, "Your proof is invalid");
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 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];
}
}