solutions/CCTF_Solutions_main/ctf.sol

186 lines
5.0 KiB
Solidity
Raw Normal View History

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