-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathMiximus.sol
125 lines (104 loc) · 3.72 KB
/
Miximus.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
pragma solidity ^0.4.19;
import "../contracts/MerkelTree.sol";
import "../contracts/Verifier.sol";
contract Miximus is MerkelTree {
mapping (bytes32 => bool) roots;
mapping (bytes32 => bool) nullifiers;
event Withdraw (address);
Verifier public zksnark_verify;
function Miximus (address _zksnark_verify) {
zksnark_verify = Verifier(_zksnark_verify);
}
function deposit (bytes32 leaf) payable {
require(msg.value == 1 ether);
insert(leaf);
roots[padZero(getRoot())] = true;
}
function withdraw (
uint[2] a,
uint[2] a_p,
uint[2][2] b,
uint[2] b_p,
uint[2] c,
uint[2] c_p,
uint[2] h,
uint[2] k,
uint[] input
) returns (address) {
address recipient = nullifierToAddress(reverse(bytes32(input[2])));
bytes32 root = padZero(reverse(bytes32(input[0]))); //)merge253bitWords(input[0], input[1]);
bytes32 nullifier = padZero(reverse(bytes32(input[2]))); //)merge253bitWords(input[2], input[3]);
require(roots[root]);
require(!nullifiers[nullifier]);
require(zksnark_verify.verifyTx(a,a_p,b,b_p,c,c_p,h,k,input));
nullifiers[nullifier] = true;
uint fee = input[4];
require(fee < 1 ether);
if (fee != 0 ) {
msg.sender.transfer(fee);
}
recipient.transfer(1 ether - fee);
Withdraw(recipient);
return(recipient);
}
function isRoot(bytes32 root) constant returns(bool) {
return(roots[root]);
}
function nullifierToAddress(bytes32 source) returns(address) {
bytes20[2] memory y = [bytes20(0), 0];
assembly {
mstore(y, source)
mstore(add(y, 20), source)
}
//trace(source, y[0], y[1]);
return(address(y[0]));
}
// libshark only allows 253 bit chunks in its output
// to overcome this we merge the first 253 bits (left) with the remaining 3 bits
// in the next variable (right)
function merge253bitWords(uint left, uint right) returns(bytes32) {
right = pad3bit(right);
uint left_msb = uint(padZero(reverse(bytes32(left))));
uint left_lsb = uint(getZero(reverse(bytes32(left))));
right = right + left_lsb;
uint res = left_msb + right;
return(bytes32(res));
}
// ensure that the 3 bits on the left is actually 3 bits.
function pad3bit(uint input) constant returns(uint) {
if (input == 0)
return 0;
if (input == 1)
return 4;
if (input == 2)
return 4;
if (input == 3)
return 6;
return(input);
}
function getZero(bytes32 x) returns(bytes32) {
//0x1111111111111111111111113fdc3192693e28ff6aee95320075e4c26be03308
return(x & 0x000000000000000000000000000000000000000000000000000000000000000F);
}
function padZero(bytes32 x) returns(bytes32) {
//0x1111111111111111111111113fdc3192693e28ff6aee95320075e4c26be03308
return(x & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0);
}
function reverseByte(uint a) public pure returns (uint) {
uint c = 0xf070b030d0509010e060a020c0408000;
return (( c >> ((a & 0xF)*8)) & 0xF0) +
(( c >> (((a >> 4)&0xF)*8) + 4) & 0xF);
}
//flip endinaness
function reverse(bytes32 a) public pure returns(bytes32) {
uint r;
uint i;
uint b;
for (i=0; i<32; i++) {
b = (uint(a) >> ((31-i)*8)) & 0xff;
b = reverseByte(b);
r += b << (i*8);
}
return bytes32(r);
}
}