Ring signatures for Pseudonym Pairs

in #bitnation6 years ago (edited)

Code to add ring signatures to Pseudonym Pairs now finished, based on laundromat.sol from Andrew "blackyblack" Lekar.

How it works, after the pseudonym event, everyone has to mix, the whole global population has to mix their proofs, and do so by joining mixers, incrementally, a new mixer created once the previous one is full. Very simple. There are two sets of mixers, one for NYM, another for registering for the next pseudonym event. Once a mixer group has formed, anyone can finish the transfer of their keys regardless of everyone else, so no risk of getting "locked in". The strays, as in the people who are at the end in case the population size is not evenly divisible by factors of 4, are sorted into a mixer of 3 people, at most three mixers with 3 people.

mapping(address => bool) verified;
uint totalVerified;

/* Two separate mixers, one for the NYM token and 
   one to register for the next pseudonym event */

mapping(uint => address[4][2]) mixer;
mapping(address => uint[2]) mixerIndex;
uint[2] mixerCount = [1, 1];

mapping(address => uint[2]) publicKey;

uint constant internal Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240;
uint constant internal Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424;

address internal constant arithAddress = 0x600ad7b57f3e6aeee53acb8704a5ed50b60cacd6;
ArithLib private arithContract = ArithLib(arithAddress);

struct MixerInfo {

    address sender;
    uint Ix;
    uint Iy;
    uint[] signature;
    uint[] ring1;
    uint[] ring2;
    
    uint step;
    uint prevStep;
}

mapping (address => MixerInfo[2]) private withdraws;
mapping (uint => bool) private consumed;

event mixingErrorMessage(string message);

function attachPublicKey(bytes _publicKey) {
    require(verified[msg.sender] == true);
    require(publicKey[msg.sender][0] == 0);
    require(address(keccak256(_publicKey) == msg.sender);

    uint pubkey1;
    uint pubkey2;
    assembly {
    pubkey1 := mload(add(publicKey,0x20))
    pubkey2 := mload(add(publicKey,0x40))
    }
    publicKey[msg.sender][0] = pubkey1;
    publicKey[msg.sender][1] = pubkey2;
}

function joinNymMixer() public {
    joinMixer(0);
}
function joinRegMixer() public {
    joinMixer(1);
}
function joinMixer(uint _mixer) internal {
    require(publicKey[msg.sender][0] != 0);
    require(mixerIndex[msg.sender][_mixer] == 0);
    uint index = mixer[mixerCount[_mixer]].length;
    mixer[mixerCount[_mixer]][index] = msg.sender;
    mixerIndex[msg.sender][_mixer] = mixerCount[_mixer];
    uint mixerSize = getMixerSize(_mixer);
    if(index == mixerSize - 1) { mixerCount[_mixer]++; }
}
/* sort the last couple of people i.e. modulo remainder */
function getMixerSize(uint _mixer) returns (uint) {
    if(totalVerified % 4 == 1) {
        if((mixerCount[_mixer] * 4) >= totalVerified - 9) return 3;
        else return 4;
    }
    if(totalVerified % 4 == 2) {
        if((mixerCount[_mixer] * 4) >= totalVerified - 6) return 3;
        else return 4;
    }
    if(totalVerified % 4 == 3) {
        if((mixerCount[_mixer] * 4) == totalVerified - 3) return 3;
        else return 4;
    }
    if(totalVerified % 4 == 0) { return 4; }
}

function startNymMix(uint _mixerID, uint[] _signature, uint _x0, uint _Ix, uint _Iy) {  
    startMix(0, _mixerID, _signature, _x0, _Ix, _Iy);
}
function NymMixStep(uint _mixerID) {   
    mixStep(0, _mixerID);
}
function FinalizeNymMix(uint _mixerID) returns (bool) { 
    return finalizeMix(0, _mixerID);
}
function StartRegMix(uint _mixerID, uint[] _signature, uint _x0, uint _Ix, uint _Iy) { 
    startMix(1, _mixerID, _signature, _x0, _Ix, _Iy);
}
function RegMixStep(uint _mixerID) {   
    mixStep(1, _mixerID);
}
function FinalizRegMix(uint _mixerID) returns (bool) {
    return finalizeMix(1, _mixerID);
}

function startMix(uint _mixer, uint _mixerID, uint[] _signature, uint _x0, uint _Ix, uint _Iy) internal {
    require(mixerCount[_mixer] > _mixerID);
    require(consumed[uint(sha3([_Ix, _Iy]))] == false);

    MixerInfo withdraw = withdraws[msg.sender][_mixer];

    withdraw.sender = msg.sender;
    withdraw.Ix = _Ix;
    withdraw.Iy = _Iy;
    withdraw.signature = _signature;

    withdraw.ring1.length = 0;
    withdraw.ring2.length = 0;
    withdraw.ring1.push(_x0);
    withdraw.ring2.push(uint(sha3(_x0)));
    
    withdraw.step = 1;
    withdraw.prevStep = 0;
}

function mixStep(uint _mixer, uint _mixerID) internal {
    MixerInfo withdraw = withdraws[msg.sender][_mixer];

    //throw if existing witdhraw not started
    require(withdraw.step != 0);
    require(withdraw.step <= mixer[_mixerID][_mixer].length);
    require(consumed[uint(sha3([withdraw.Ix, withdraw.Iy]))] == false);

    uint k1x;
    uint k1y;
    uint k1z;
    uint k2x;
    uint k2y;
    uint k2z;
    uint pub1x;
    uint pub1y;
    
    address[] people = mixer[_mixerID][_mixer];
    address participant = people[withdraw.step % participants];

    (k1x, k1y, k1z) = arithContract.jmul(Gx, Gy, 1,
        withdraw.signature[withdraw.prevStep % participants]);
    (k2x, k2y, k2z) = arithContract.jmul(
        publicKey[participant][0],
        publicKey[participant][1], 1,
        withdraw.ring2[withdraw.prevStep % participants]);
    (k1x, k1y, k1z) = arithContract.jsub(k1x, k1y, k1z, k2x, k2y, k2z);
    (pub1x, pub1y) = arithContract.jdecompose(k1x, k1y, k1z);
    (k1x, k1y) = arithContract.hash_pubkey_to_pubkey(
        publicKey[participant][0],
        publicKey[participant][1]);
    (k1x, k1y, k1z) = arithContract.jmul(k1x, k1y, 1,
        withdraw.signature[withdraw.prevStep % participants]);
    (k2x, k2y, k2z) = arithContract.jmul(withdraw.Ix, withdraw.Iy, 1,
        withdraw.ring2[withdraw.prevStep % participants]);
    (k1x, k1y, k1z) = arithContract.jsub(k1x, k1y, k1z, k2x, k2y, k2z);
    (k1x, k1y) = arithContract.jdecompose(k1x, k1y, k1z);
    withdraw.ring1.push(uint(sha3([uint(withdraw.sender), pub1x, pub1y, k1x, k1y])));
    withdraw.ring2.push(uint(sha3(uint(sha3([uint(withdraw.sender), pub1x, pub1y, k1x, k1y])))));
    withdraw.step++;
    withdraw.prevStep++;
}

function finalizeMix(uint _mixer, uint _mixerID) internal returns (bool) {
    MixerInfo withdraw = withdraws[msg.sender][_mixer];
    
    require(withdraw.step == mixer[_mixerID][_mixer].length + 1);
    require(consumed[uint(sha3([withdraw.Ix, withdraw.Iy]))] == false);

    if(withdraw.ring1[participants] != withdraw.ring1[0]) {
        
        mixingErrorMessage("Wrong signature");
        return false;
    }
    if(withdraw.ring2[participants] != withdraw.ring2[0]) {
        
        mixingErrorMessage("Wrong signature");
        return false;
    }
    
    withdraw.step++;
    consumed[uint(sha3([withdraw.Ix, withdraw.Iy]))] = true;

    transferOwnership(_mixer, withdraw.sender);
    return true;
}

transferOwnership(uint _mixer, address _newPublicKey) internal {
    if(_mixer == 0) {
        /* issue a NYM token to the new public key */
        NYM[_newPublicKey] = true;
    }
    if(_mixer == 1) {
        /* register for the next pseudonym event with the new public key */
    }
}

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63562.42
ETH 2649.15
USDT 1.00
SBD 2.77