Skip to content

Instantly share code, notes, and snippets.

@resilience-me
Last active November 8, 2018 15:57
Show Gist options
  • Save resilience-me/75cf3df0d7276e8e6b669a77e90cd99a to your computer and use it in GitHub Desktop.
Save resilience-me/75cf3df0d7276e8e6b669a77e90cd99a to your computer and use it in GitHub Desktop.
contract MazeHashFunction {
function generateRandomNumber(uint _treasureMap) view internal returns (uint) {
bytes memory randomNumber = new bytes(32);
bytes memory treasureMapInBytes = toBytes(_treasureMap);
uint8 nextByteInTreasureMap = uint8(treasureMapInBytes[31]);
uint8 pointerToNextPosition = nextByteInTreasureMap;
for(uint i = 31; i >0; i--) {
uint nextHashInLabyrinth = uint(blockhash(block.number - 1 - pointerToNextPosition));
bytes memory blockHashToBytes = toBytes(nextHashInLabyrinth);
uint8 byteFromBlockhash = uint8(blockHashToBytes[i]);
nextByteInTreasureMap = uint8(treasureMapInBytes[i]);
uint8 nextRandomNumber = nextByteInTreasureMap ^ byteFromBlockhash;
randomNumber[i] = bytes1(nextRandomNumber);
pointerToNextPosition = nextRandomNumber;
}
return toUint(randomNumber);
}
function toBytes(uint256 x) pure internal returns (bytes b) {
b = new bytes(32);
assembly { mstore(add(b, 32), x) }
}
function toUint(bytes x) pure internal returns (uint b) {
assembly {
b := mload(add(x, 0x20))
}
}
}
contract PseudonymPairs is MazeHashFunction {
enum State { interlude, pseudonymEvent, eventFinished, endOfPeriod }
uint[4] timeperiods;
mapping(uint => uint) randomHourMechanism;
uint randomHour; // The exact hour of the event cycles by random over 24 hours
uint genesisTimestamp = 1545523200; // Saturday 22 December 2018 00:00:00, pseudonym events
// scheduled to random hour between 00:00 and 23:59 on saturdays
function setRandomHour() internal {
entropy = generateRandomNumber(entropy);
uint stepIn24HourCycle = eventCounter % 24;
uint randomNumber = entropy % (24 - stepIn24HourCycle);
uint randomClockstroke = stepIn24HourCycle + randomNumber;
randomHourMechanism[randomClockstroke] = randomHourMechanism[stepIn24HourCycle]; // Update the index that is used for cycling through random hours
randomHour = randomClockstroke;
timeperiods[2] = 28 days - randomHour;
timeperiods[1] = 28 days - randomHour - 20 minutes;
}
modifier atTime(State _inState, State _nextState) {
require(now > getTime(_inState));
require(now < getTime(_nextState));
_;
}
function getTime(State _state) view returns (uint) {
return genesisTimestamp + (timeperiods[3] * eventCounter) + timeperiods[uint(_state)];
}
modifier incrementEventCounter {
if(now > getTime(State.endOfPeriod)) eventCounter++;
_;
}
constructor() {
genesisTimestamp = now;
timeperiods[3] = 28 days; // 13 events per year, 364 day year. The pseudonym event is on a saturday, always
timeperiods[2] = 28 days - randomHour; // This varies with randomHour, adjusted every new pseudonym month
timeperiods[1] = 28 days - randomHour - 20 minutes; // The pseudonym event lasts 20 minutes
timeperiods[0] = 0;
}
function register(uint _nym) internal atTime(State.interlude, State.pseudonymEvent) { }
mapping(uint => uint) evenNumbersIndex; // The pair that a given pseudonymID maps to, list is shuffled with each new person who invokes sortMe()
mapping(uint => uint) unevenNumbersIndex; // The index is split over even and uneven numbers, to map to pairs of two people
mapping(address => uint) pseudonymID;
mapping(uint => address) pseudonymIndex;
uint totalSorted;
uint totalPairs;
mapping(uint => uint) virtualBorder; // immigrantID mapped to evenNumbers, hitch-hikes on a registered person, and the shuffling on their end
mapping(address => uint) immigrantID;
mapping(uint => address) immigrantIndex;
uint totalImmigrants;
uint entropy;
function sortMe() atTime(State.interlude, State.pseudonymEvent) {
require(pseudonymID[msg.sender] == 0);
totalSorted++;
pseudonymID[msg.sender] = totalSorted;
pseudonymIndex[totalSorted] = msg.sender;
entropy = generateRandomNumber(entropy);
// Map even and uneven numbers in separate indices, each integer representing a pair with two people
if(totalSorted % 2 == 0) {
uint randomNumber = 1 + (entropy % totalPairs);
evenNumbersIndex[randomNumber] = totalPairs;
evenNumbersIndex[totalPairs] = randomNumber;
totalPairs++;
}
if(totalSorted % 2 == 1) {
uint randomNumber = 1 + (entropy % totalPairs);
unevenNumbersIndex[randomNumber] = totalPairs;
unevenNumbersIndex[totalPairs] = randomNumber;
}
}
function optIn() atTime(State.interlude, State.pseudonymEvent) {
require(totalPairs >= 1);
require(totalPairs > totalImmigrants);
require(immigrantID[msg.sender] == 0);
require(borderToken.balanceOf[msg.sender] >= 1);
borderToken.balanceOf[msg.sender]--;
totalImmigrants++;
immigrantID[msg.sender] = totalImmigrants;
immigrantIndex[totalImmigrants] = msg.sender;
entropy = generateRandomNumber(entropy);
uint randomNumber = 1 + (entropy % (totalPairs - totalImmigrants));
uint randomPair = totalImmigrants + randomNumber; // Mapped to evenNumbers, hitch-hikes on a registered person, and the shuffling on their end
// Prune the list with randomPair, adding the pair from the beginning to its position
if(virtualBorder[randomPair] == 0) virtualBorder[randomPair] = randomPair;
if(virtualBorder[totalImmigrants] == 0) virtualBorder[totalImmigrants] = totalImmigrants;
uint indexedPosition = virtualBorder[randomPair];
virtualBorder[indexedPosition] = virtualBorder[totalImmigrants];
// Assign the person to randomPair
virtualBorder[totalImmigrants] = randomPair;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment