# Thirty Five

We are hackers, We have our own ways!

// https://ciphershastra.com/ThirtyFive.html
pragma solidity ^0.8.11;

import "./ECDSA.sol";

contract ThirtyFive {
    using ECDSA for bytes32;

    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); 
    bytes32 public constant SIGNING_TYPEHASH = keccak256("SIGNING(uint16 nonce,uint256 expiry)");
    bytes32 public immutable DOMAIN_SEPARATOR;
    bytes32 public immutable name;
    bytes32 public immutable version;

    mapping(address=>uint24) public nonces;
    mapping(address=>bytes32) internal verificationTokens;
    mapping(address=>bool) internal isTokenGenerated;
    mapping(bytes32=>bool) internal identifiers;
    uint public completed;
    event TokenGen(address indexed signer, bytes32 indexed token);

    constructor(string memory _name, string memory _version) {
        bytes32 name_ = keccak256(bytes(_name));
        bytes32 version_ = keccak256(bytes(_version));
        name = name_;
        version = version_;
        completed = 0;
        uint chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, name_, version_, chainId, address(this)));
    }

    function signItLikeYouMeanIt(uint16 nonce, uint deadline, bytes memory signature) external {
        require(block.timestamp <= deadline, "Expired");
        require(nonce == nonces[msg.sender]+1, "Invalid Nonce");
        bytes32 structHash = keccak256(abi.encode(SIGNING_TYPEHASH, nonce, deadline));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash));
        address signer = digest.recover(signature);
        require(signer == msg.sender, "Only Self Signed Signatures are allowed");
        bytes32 slot = keccak256(abi.encode(msg.sender, 0));
        assembly{
            sstore(slot, calldataload(4))
        }
    }

    function giveMeMyToken() external {
        if (nonces[msg.sender] > 0x5014C3 && !isTokenGenerated[msg.sender]) {
            bytes32 token = keccak256(abi.encode(msg.sender,block.timestamp));
            verificationTokens[msg.sender] = token;
            isTokenGenerated[msg.sender]=true;
            emit TokenGen(msg.sender, token);
        }
    }

    function pwn(bytes32 token) external {
        require(token!=bytes32(0), "No Token Yet");
        require(token == verificationTokens[msg.sender], "Invalid Token");
        bytes32 id = keccak256(msg.data);
        require(!identifiers[id], "Already executed");
        identifiers[id] = true;
        completed += 1;
    }

    function HackerWho() external view returns(string memory) {
        uint counter = completed;
        if (counter > 0 && counter <= 2){
            return "Yayyy! You solved the challenge";
        }
        else if (counter > 2) {
            return "Hello Hacker";
        }
        else { return "Not yet" ;}
    }
}