The game theory in Pseudonym Pairs is that pairs are broken if there is a conflict. As long as people play nice, people only meet 1 on 1. Mob rule is only introduced if there is a conflict, 2 over 1. That makes the protocol maximally egalitarian. Like, I think you would have a hard time coming up with a more egalitarian coordination protocol.
That rule, 1-on-1 unless conflict, was inspired by Susanne Tarkowski Tempelhof.
In the code here, you see that you can break up your pair as long as both the peers have not signed the other.
uint[][2] pairIndex;
struct Reg {
bool rank;
uint id;
bool[2] signatures;
bool verified;
}
mapping(address => Reg) accountID;
mapping(bool => mapping(uint => address) accountIndex;
function assignID(bool _rank) internal {
pairIndex[_rank].length++;
accountID[msg.sender].rank = _rank;
accountID[msg.sender].id = pairIndex[_rank].length;
}
function breakPair() {
require(accountID[msg.sender].rank == true && ! accountID[msg.sender].signatures[0] == accountID[msg.sender].signatures[1] == true);
delete accountIndex[true][2*getPair(msg.sender)];
}
The system is built around the 28 day schedule. There is no other time limits imposed, for anything. The smart contract does not even say how long the event is, there has to be an informal consensus around that, or semi-formal, not just dictated by the ledger, as it adds nothing to the smart contract, there is no functions that need to be prevented in time other than along the 28 day schedule.
Scheduling is very simple, genesis set to 07:00 UTC on a Saturday, event on the weekend for all time zones on Earth, time boundaries 19:00 Friday UTC-12 and 21:00 Sunday UTC+14.
uint genesisEvent = 1580540400;
uint[] clockwork;
uint hour;
function eventScheduler() internal {
if(clockwork.length == 0) clockwork.length = 24;
uint randomHour = getRandomNumber() % clockwork.length;
if(clockwork[randomHour] == 0) hour = randomHour;
else hour = clockwork[randomHour];
if(clockwork[clockwork.length - 1] == 0) clockwork[randomHour] = clockwork.length - 1;
else clockwork[randomHour] = clockwork[clockwork.length - 1];
clockwork.length--;
}
Verification is likewise simple. In Pseudonym Pairs, you can upload signatures from people who verified you at any time after an event up to the next event, 28 days. Very simple. Ideally, as fast as possible, but there are no time constraints other than 4 weeks, because there does not need to be any other constraints so there is no reason to add any.
function verify(address _account, address _signer) internal {
uint pairID = getPair(_account);
require(accountIndex[true][pairID*2] != 0 && pairID == getPair(_signer) && accountData[_signer].rank == true);
accountData[_account].signatures[getIndex(_signer)%2] = true;
}
function verifyAccount(address _account) {
verify(_account, msg.sender);
}
function uploadSignature(address _account, bytes _signature) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(_signature,0x20))
s := mload(add(_signature,0x40))
v := and(mload(add(_signature, 0x41)), 0xFF)
}
if (v < 27) v += 27;
bytes32 msgHash = keccak256(_account, eventCounter - 1);
verify(_account, ecrecover(msgHash, v, r, s))
}
Talk with your peer over any medium (video obviously assumed, but, any platform/protocol), sign each other using simple basic cryptographic functions, then just upload the proof whenever you want to (28 days being the only limit. )
In Pseudonym Pairs, once verified, you collect your personhood. To make mixing easy, you get two tokens, one to register for the next event, and another to lock as your proof-of-personhood. Both should ideally be mixed, how people do that is not dictated by the PP smart contract.
function collectPersonhood() public {
require(registry[msg.sender].verified == false);
uint pairID = getPair(msg.sender);
address peer1 = regIndex[true][2 * pairID];
address peer2 = regIndex[true][2 * pairID - 1];
require(registry[peer1].signatures[0] == true && registry[peer2].signatures[0] == true);
if(registry[msg.sender].rank != true) require(registry[msg.sender].signatures[0] == true && registry[msg.sender].signatures[1] == true);
verifiedToken[msg.sender] += 1;
registrationToken[msg.sender] += 1;
registry[msg.sender].verified = true;
}