# Shilpkaar
The doors are locked, Only a Worthy Shilpkaar can craft the Master Key from pieces. Are you the one?
// ref. https://ciphershastra.com/shilpkaar.html
pragma solidity ^0.4.26;
contract Shilpkaar {
address private garbageAddress;
bool private gate1Unlocked;
uint16 private gateKey1;
uint72 public rouletteStartTime;
uint64 private gateKey2;
uint64 private gateKey3;
bool private gate2Unlocked;
uint64 private gateKey4;
uint56 private gateKey5;
uint256 private rouletteSecretNumber;
uint256 private buffer1;
uint256 private buffer2;
uint256 private garbageDivisor;
uint256 private garbageMultiplier;
uint256 private masterDivisor;
uint256 private masterMultiplier;
uint256 public masterNonce;
uint256 public garbageNonce;
uint72 private backupRouletteTIme;
struct regInfo{
bytes32 name;
bytes32 password;
uint256 lastPlayed;
}
mapping(address=>regInfo) public userRecords;
mapping(address=>bool) public shilpkaar;
mapping(address=>uint72) public timeToRoll;
bool public completed;
address public owner;
function Shilpkaar(uint256 duration) {
rouletteStartTime = uint72(block.timestamp + duration);
backupRouletteTIme = rouletteStartTime;
shilpkaar[msg.sender] = true;
owner = msg.sender;
masterDivisor = 60001;
masterMultiplier = 60001;
garbageDivisor = 2**160-2**153;
garbageMultiplier = 2**160-2**153;
completed = false;
}
function unlock(bytes32 _name, bytes32 _password) external {
regInfo regRecord;
regRecord.name = _name;
regRecord.password = _password;
require(gate1Unlocked && gate2Unlocked, "Gates Not Unlocked");
require(uint256(garbageAddress) > 2**153 + garbageNonce && uint256(garbageAddress) <= 2**160 - ((garbageDivisor-1) - garbageNonce), "Problem With garbageAddress");
require(gateKey3 < uint256(uint64(-1))*49/100 && gateKey4 < uint256(uint64(-1))*51 / 100 && probablyPrime(gateKey3) && probablyPrime(gateKey4), "Problem with gateKeys");
uint256 masterKey = uint256(gateKey1)+uint256(gateKey2)+uint256(gateKey3)+uint256(gateKey4)+uint256(gateKey5);
require(masterKey > (2**65+2**56) + masterNonce && masterKey < (2**65+2**56+2**16) - ((masterDivisor-1)- masterNonce), "Problem with masterkey");
userRecords[msg.sender] = regRecord;
shilpkaar[msg.sender] = true;
timeToRoll[msg.sender] = rouletteStartTime;
reset();
}
function roulette(uint256 _secretNumber) external {
require(shilpkaar[msg.sender], "Are you a Shilpkaar?");
require(block.timestamp>=timeToRoll[msg.sender], "Problem with timeToRoll");
timeToRoll[msg.sender]=backupRouletteTIme;
regInfo regRecord;
regRecord.lastPlayed = block.timestamp;
require(_secretNumber == rouletteSecretNumber, "Secret Number doesn't match");
userRecords[msg.sender] = regRecord;
completed = true;
reset();
}
function rand() internal view returns(uint256, uint256) {
uint256 seed = uint256(keccak256(
block.timestamp + block.difficulty +
((uint256(keccak256(block.coinbase))) / (now)) +
block.gaslimit +
((uint256(keccak256(msg.sender))) / (now)) +
block.number));
return (seed - ((seed / garbageDivisor) * garbageMultiplier),
seed - ((seed / masterDivisor) * masterMultiplier));
}
function reset() internal {
garbageAddress = address(0);
gate1Unlocked = false;
gate2Unlocked = false;
rouletteStartTime = backupRouletteTIme;
gateKey1 = 0;
gateKey2 = 0;
gateKey3 = 0;
gateKey4 = 0;
gateKey5 = 0;
rouletteSecretNumber = 0;
(garbageNonce, masterNonce) = rand();
regInfo regRecord = userRecords[msg.sender];
regRecord.name = bytes32(0);
regRecord.password = bytes32(0);
}
function updateRouletteTime(uint72 _rouletteStartTIme) external {
require(owner == msg.sender);
rouletteStartTime = _rouletteStartTIme;
backupRouletteTIme = _rouletteStartTIme;
}
function updateSeed(uint256 _garbageDivisor, uint256 _garbageMultiplier,
uint256 _masterDivisor, uint256 _masterMultiplier) external {
require(owner == msg.sender);
garbageDivisor = _garbageDivisor;
garbageMultiplier = _garbageMultiplier;
masterDivisor = _masterDivisor;
masterMultiplier = _masterMultiplier;
}
function updateNonce(uint256 _garbageNonce, uint256 _masterNonce) external {
require(owner == msg.sender);
masterNonce = _masterNonce;
garbageNonce = _garbageNonce;
}
function transferOwnership(address _newOwner) external{
require(owner == msg.sender);
owner = _newOwner;
}
function probablyPrime(uint256 n) internal pure returns (bool) {
uint256 prime = 2;
if (n == 2 || n == 3) {
return true;
}
if (n % 2 == 0 || n < 2) {
return false;
}
uint256[2] memory values = getValues(n);
uint256 s = values[0];
uint256 d = values[1];
uint256 x = fastModularExponentiation(prime, d, n);
if (x == 1 || x == n - 1) {
return true;
}
for (uint256 i = s - 1; i > 0; i--) {
x = fastModularExponentiation(x, 2, n);
if (x == 1) {
return false;
}
if (x == n - 1) {
return true;
}
}
return false;
}
function fastModularExponentiation(uint256 a, uint256 b, uint256 n)
internal pure returns (uint256) {
a = a % n;
uint256 result = 1;
uint256 x = a;
while(b > 0){
uint256 leastSignificantBit = b % 2;
b = b / 2;
if (leastSignificantBit == 1) {
result = result * x;
result = result % n;
}
x = mul(x, x);
x = x % n;
}
return result;
}
// Write (n - 1) as 2^s * d
function getValues(uint256 n) internal pure returns (uint256[2] memory) {
uint256 s = 0;
uint256 d = n - 1;
while (d % 2 == 0) {
d = d / 2;
s++;
}
uint256[2] memory ret;
ret[0] = s;
ret[1] = d;
return ret;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
}