Created
August 13, 2018 04:07
-
-
Save phuctu1901/07cdcd8c211b80c1e67e4b57ee48fc3b to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.24+commit.e67f0147.js&optimize=false&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.3; | |
/** | |
* @title ECCMath | |
* | |
* Functions for working with integers, curve-points, etc. | |
* | |
* @author Andreas Olofsson ([email protected]) | |
*/ | |
library ECCMath { | |
/// @dev Modular inverse of a (mod p) using euclid. | |
/// "a" and "p" must be co-prime. | |
/// @param a The number. | |
/// @param p The mmodulus. | |
/// @return x such that ax = 1 (mod p) | |
function invmod(uint a, uint p) internal constant returns (uint) { | |
if (a == 0 || a == p || p == 0) | |
throw; | |
if (a > p) | |
a = a % p; | |
int t1; | |
int t2 = 1; | |
uint r1 = p; | |
uint r2 = a; | |
uint q; | |
while (r2 != 0) { | |
q = r1 / r2; | |
(t1, t2, r1, r2) = (t2, t1 - int(q) * t2, r2, r1 - q * r2); | |
} | |
if (t1 < 0) | |
return (p - uint(-t1)); | |
return uint(t1); | |
} | |
/// @dev Modular exponentiation, b^e % m | |
/// Basically the same as can be found here: | |
/// https://github.com/ethereum/serpent/blob/develop/examples/ecc/modexp.se | |
/// @param b The base. | |
/// @param e The exponent. | |
/// @param m The modulus. | |
/// @return x such that x = b**e (mod m) | |
function expmod(uint b, uint e, uint m) internal constant returns (uint r) { | |
if (b == 0) | |
return 0; | |
if (e == 0) | |
return 1; | |
if (m == 0) | |
throw; | |
r = 1; | |
uint bit = 2 ** 255; | |
bit = bit; | |
assembly { | |
loop: | |
jumpi(end, iszero(bit)) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, bit)))), m) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, div(bit, 2))))), m) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, div(bit, 4))))), m) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, div(bit, 8))))), m) | |
bit := div(bit, 16) | |
jump(loop) | |
end: | |
} | |
} | |
/// @dev Converts a point (Px, Py, Pz) expressed in Jacobian coordinates to (Px", Py", 1). | |
/// Mutates P. | |
/// @param P The point. | |
/// @param zInv The modular inverse of "Pz". | |
/// @param z2Inv The square of zInv | |
/// @param prime The prime modulus. | |
/// @return (Px", Py", 1) | |
function toZ1(uint[3] memory P, uint zInv, uint z2Inv, uint prime) internal constant { | |
P[0] = mulmod(P[0], z2Inv, prime); | |
P[1] = mulmod(P[1], mulmod(zInv, z2Inv, prime), prime); | |
P[2] = 1; | |
} | |
/// @dev See _toZ1(uint[3], uint, uint). | |
/// Warning: Computes a modular inverse. | |
/// @param PJ The point. | |
/// @param prime The prime modulus. | |
/// @return (Px", Py", 1) | |
function toZ1(uint[3] PJ, uint prime) internal constant { | |
uint zInv = invmod(PJ[2], prime); | |
uint zInv2 = mulmod(zInv, zInv, prime); | |
PJ[0] = mulmod(PJ[0], zInv2, prime); | |
PJ[1] = mulmod(PJ[1], mulmod(zInv, zInv2, prime), prime); | |
PJ[2] = 1; | |
} | |
} | |
library Secp256k1 { | |
// TODO separate curve from crypto primitives? | |
// Field size | |
uint constant pp = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; | |
// Base point (generator) G | |
uint constant Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; | |
uint constant Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8; | |
// Order of G | |
uint constant nn = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; | |
// Cofactor | |
// uint constant hh = 1; | |
// Maximum value of s | |
uint constant lowSmax = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0; | |
// For later | |
// uint constant lambda = "0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72"; | |
// uint constant beta = "0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"; | |
/// @dev See Curve.onCurve | |
function onCurve(uint[2] P) internal constant returns (bool) { | |
uint p = pp; | |
if (0 == P[0] || P[0] == p || 0 == P[1] || P[1] == p) | |
return false; | |
uint LHS = mulmod(P[1], P[1], p); | |
uint RHS = addmod(mulmod(mulmod(P[0], P[0], p), P[0], p), 7, p); | |
return LHS == RHS; | |
} | |
/// @dev See Curve.isPubKey | |
function isPubKey(uint[2] memory P) internal constant returns (bool isPK) { | |
isPK = onCurve(P); | |
} | |
/// @dev See Curve.isPubKey | |
// TODO: We assume we are given affine co-ordinates for now | |
function isPubKey(uint[3] memory P) internal constant returns (bool isPK) { | |
uint[2] memory a_P; | |
a_P[0] = P[0]; | |
a_P[1] = P[1]; | |
isPK = onCurve(a_P); | |
} | |
/// @dev See Curve.validateSignature | |
function validateSignature(bytes32 message, uint[2] rs, uint[2] Q) internal constant returns (bool) { | |
uint n = nn; | |
uint p = pp; | |
if(rs[0] == 0 || rs[0] >= n || rs[1] == 0 || rs[1] > lowSmax) | |
return false; | |
if (!isPubKey(Q)) | |
return false; | |
uint sInv = ECCMath.invmod(rs[1], n); | |
uint[3] memory u1G = _mul(mulmod(uint(message), sInv, n), [Gx, Gy]); | |
uint[3] memory u2Q = _mul(mulmod(rs[0], sInv, n), Q); | |
uint[3] memory P = _add(u1G, u2Q); | |
if (P[2] == 0) | |
return false; | |
uint Px = ECCMath.invmod(P[2], p); // need Px/Pz^2 | |
Px = mulmod(P[0], mulmod(Px, Px, p), p); | |
return Px % n == rs[0]; | |
} | |
/// @dev See Curve.compress | |
function compress(uint[2] P) internal constant returns (uint8 yBit, uint x) { | |
x = P[0]; | |
yBit = P[1] & 1 == 1 ? 1 : 0; | |
} | |
/// @dev See Curve.decompress | |
function decompress(uint8 yBit, uint x) internal constant returns (uint[2] P) { | |
uint p = pp; | |
var y2 = addmod(mulmod(x, mulmod(x, x, p), p), 7, p); | |
var y_ = ECCMath.expmod(y2, (p + 1) / 4, p); | |
uint cmp = yBit ^ y_ & 1; | |
P[0] = x; | |
P[1] = (cmp == 0) ? y_ : p - y_; | |
} | |
// Point addition, P + Q | |
// inData: Px, Py, Pz, Qx, Qy, Qz | |
// outData: Rx, Ry, Rz | |
function _add(uint[3] memory P, uint[3] memory Q) internal constant returns (uint[3] memory R) { | |
if(P[2] == 0) | |
return Q; | |
if(Q[2] == 0) | |
return P; | |
uint p = pp; | |
uint[4] memory zs; // Pz^2, Pz^3, Qz^2, Qz^3 | |
zs[0] = mulmod(P[2], P[2], p); | |
zs[1] = mulmod(P[2], zs[0], p); | |
zs[2] = mulmod(Q[2], Q[2], p); | |
zs[3] = mulmod(Q[2], zs[2], p); | |
uint[4] memory us = [ | |
mulmod(P[0], zs[2], p), | |
mulmod(P[1], zs[3], p), | |
mulmod(Q[0], zs[0], p), | |
mulmod(Q[1], zs[1], p) | |
]; // Pu, Ps, Qu, Qs | |
if (us[0] == us[2]) { | |
if (us[1] != us[3]) | |
return; | |
else { | |
return _double(P); | |
} | |
} | |
uint h = addmod(us[2], p - us[0], p); | |
uint r = addmod(us[3], p - us[1], p); | |
uint h2 = mulmod(h, h, p); | |
uint h3 = mulmod(h2, h, p); | |
uint Rx = addmod(mulmod(r, r, p), p - h3, p); | |
Rx = addmod(Rx, p - mulmod(2, mulmod(us[0], h2, p), p), p); | |
R[0] = Rx; | |
R[1] = mulmod(r, addmod(mulmod(us[0], h2, p), p - Rx, p), p); | |
R[1] = addmod(R[1], p - mulmod(us[1], h3, p), p); | |
R[2] = mulmod(h, mulmod(P[2], Q[2], p), p); | |
} | |
// Point addition, P + Q. P Jacobian, Q affine. | |
// inData: Px, Py, Pz, Qx, Qy | |
// outData: Rx, Ry, Rz | |
function _addMixed(uint[3] memory P, uint[2] memory Q) internal constant returns (uint[3] memory R) { | |
if(P[2] == 0) | |
return [Q[0], Q[1], 1]; | |
if(Q[1] == 0) | |
return P; | |
uint p = pp; | |
uint[2] memory zs; // Pz^2, Pz^3, Qz^2, Qz^3 | |
zs[0] = mulmod(P[2], P[2], p); | |
zs[1] = mulmod(P[2], zs[0], p); | |
uint[4] memory us = [ | |
P[0], | |
P[1], | |
mulmod(Q[0], zs[0], p), | |
mulmod(Q[1], zs[1], p) | |
]; // Pu, Ps, Qu, Qs | |
if (us[0] == us[2]) { | |
if (us[1] != us[3]) { | |
P[0] = 0; | |
P[1] = 0; | |
P[2] = 0; | |
return; | |
} | |
else { | |
_double(P); | |
return; | |
} | |
} | |
uint h = addmod(us[2], p - us[0], p); | |
uint r = addmod(us[3], p - us[1], p); | |
uint h2 = mulmod(h, h, p); | |
uint h3 = mulmod(h2, h, p); | |
uint Rx = addmod(mulmod(r, r, p), p - h3, p); | |
Rx = addmod(Rx, p - mulmod(2, mulmod(us[0], h2, p), p), p); | |
R[0] = Rx; | |
R[1] = mulmod(r, addmod(mulmod(us[0], h2, p), p - Rx, p), p); | |
R[1] = addmod(R[1], p - mulmod(us[1], h3, p), p); | |
R[2] = mulmod(h, P[2], p); | |
} | |
// Same as addMixed but params are different and mutates P. | |
function _addMixedM(uint[3] memory P, uint[2] memory Q) internal constant { | |
if(P[1] == 0) { | |
P[0] = Q[0]; | |
P[1] = Q[1]; | |
P[2] = 1; | |
return; | |
} | |
if(Q[1] == 0) | |
return; | |
uint p = pp; | |
uint[2] memory zs; // Pz^2, Pz^3, Qz^2, Qz^3 | |
zs[0] = mulmod(P[2], P[2], p); | |
zs[1] = mulmod(P[2], zs[0], p); | |
uint[4] memory us = [ | |
P[0], | |
P[1], | |
mulmod(Q[0], zs[0], p), | |
mulmod(Q[1], zs[1], p) | |
]; // Pu, Ps, Qu, Qs | |
if (us[0] == us[2]) { | |
if (us[1] != us[3]) { | |
P[0] = 0; | |
P[1] = 0; | |
P[2] = 0; | |
return; | |
} | |
else { | |
_doubleM(P); | |
return; | |
} | |
} | |
uint h = addmod(us[2], p - us[0], p); | |
uint r = addmod(us[3], p - us[1], p); | |
uint h2 = mulmod(h, h, p); | |
uint h3 = mulmod(h2, h, p); | |
uint Rx = addmod(mulmod(r, r, p), p - h3, p); | |
Rx = addmod(Rx, p - mulmod(2, mulmod(us[0], h2, p), p), p); | |
P[0] = Rx; | |
P[1] = mulmod(r, addmod(mulmod(us[0], h2, p), p - Rx, p), p); | |
P[1] = addmod(P[1], p - mulmod(us[1], h3, p), p); | |
P[2] = mulmod(h, P[2], p); | |
} | |
// Point doubling, 2*P | |
// Params: Px, Py, Pz | |
// Not concerned about the 1 extra mulmod. | |
function _double(uint[3] memory P) internal constant returns (uint[3] memory Q) { | |
uint p = pp; | |
if (P[2] == 0) | |
return; | |
uint Px = P[0]; | |
uint Py = P[1]; | |
uint Py2 = mulmod(Py, Py, p); | |
uint s = mulmod(4, mulmod(Px, Py2, p), p); | |
uint m = mulmod(3, mulmod(Px, Px, p), p); | |
var Qx = addmod(mulmod(m, m, p), p - addmod(s, s, p), p); | |
Q[0] = Qx; | |
Q[1] = addmod(mulmod(m, addmod(s, p - Qx, p), p), p - mulmod(8, mulmod(Py2, Py2, p), p), p); | |
Q[2] = mulmod(2, mulmod(Py, P[2], p), p); | |
} | |
// Same as double but mutates P and is internal only. | |
function _doubleM(uint[3] memory P) internal constant { | |
uint p = pp; | |
if (P[2] == 0) | |
return; | |
uint Px = P[0]; | |
uint Py = P[1]; | |
uint Py2 = mulmod(Py, Py, p); | |
uint s = mulmod(4, mulmod(Px, Py2, p), p); | |
uint m = mulmod(3, mulmod(Px, Px, p), p); | |
var PxTemp = addmod(mulmod(m, m, p), p - addmod(s, s, p), p); | |
P[0] = PxTemp; | |
P[1] = addmod(mulmod(m, addmod(s, p - PxTemp, p), p), p - mulmod(8, mulmod(Py2, Py2, p), p), p); | |
P[2] = mulmod(2, mulmod(Py, P[2], p), p); | |
} | |
// Multiplication dP. P affine, wNAF: w=5 | |
// Params: d, Px, Py | |
// Output: Jacobian Q | |
function _mul(uint d, uint[2] memory P) internal constant returns (uint[3] memory Q) { | |
uint p = pp; | |
if (d == 0) // TODO | |
return; | |
uint dwPtr; // points to array of NAF coefficients. | |
uint i; | |
// wNAF | |
assembly | |
{ | |
let dm := 0 | |
dwPtr := mload(0x40) | |
mstore(0x40, add(dwPtr, 512)) // Should lower this. | |
loop: | |
jumpi(loop_end, iszero(d)) | |
jumpi(even, iszero(and(d, 1))) | |
dm := mod(d, 32) | |
mstore8(add(dwPtr, i), dm) // Don"t store as signed - convert when reading. | |
d := add(sub(d, dm), mul(gt(dm, 16), 32)) | |
even: | |
d := div(d, 2) | |
i := add(i, 1) | |
jump(loop) | |
loop_end: | |
} | |
dwPtr = dwPtr; | |
// Pre calculation | |
uint[3][8] memory PREC; // P, 3P, 5P, 7P, 9P, 11P, 13P, 15P | |
PREC[0] = [P[0], P[1], 1]; | |
var X = _double(PREC[0]); | |
PREC[1] = _addMixed(X, P); | |
PREC[2] = _add(X, PREC[1]); | |
PREC[3] = _add(X, PREC[2]); | |
PREC[4] = _add(X, PREC[3]); | |
PREC[5] = _add(X, PREC[4]); | |
PREC[6] = _add(X, PREC[5]); | |
PREC[7] = _add(X, PREC[6]); | |
uint[16] memory INV; | |
INV[0] = PREC[1][2]; // a1 | |
INV[1] = mulmod(PREC[2][2], INV[0], p); // a2 | |
INV[2] = mulmod(PREC[3][2], INV[1], p); // a3 | |
INV[3] = mulmod(PREC[4][2], INV[2], p); // a4 | |
INV[4] = mulmod(PREC[5][2], INV[3], p); // a5 | |
INV[5] = mulmod(PREC[6][2], INV[4], p); // a6 | |
INV[6] = mulmod(PREC[7][2], INV[5], p); // a7 | |
INV[7] = ECCMath.invmod(INV[6], p); // a7inv | |
INV[8] = INV[7]; // aNinv (a7inv) | |
INV[15] = mulmod(INV[5], INV[8], p); // z7inv | |
for(uint k = 6; k >= 2; k--) { // z6inv to z2inv | |
INV[8] = mulmod(PREC[k + 1][2], INV[8], p); | |
INV[8 + k] = mulmod(INV[k - 2], INV[8], p); | |
} | |
INV[9] = mulmod(PREC[2][2], INV[8], p); // z1Inv | |
for(k = 0; k < 7; k++) { | |
ECCMath.toZ1(PREC[k + 1], INV[k + 9], mulmod(INV[k + 9], INV[k + 9], p), p); | |
} | |
// Mult loop | |
while(i > 0) { | |
uint dj; | |
uint pIdx; | |
i--; | |
assembly { | |
dj := byte(0, mload(add(dwPtr, i))) | |
} | |
_doubleM(Q); | |
if (dj > 16) { | |
pIdx = (31 - dj) / 2; // These are the "negative ones", so invert y. | |
_addMixedM(Q, [PREC[pIdx][0], p - PREC[pIdx][1]]); | |
} | |
else if (dj > 0) { | |
pIdx = (dj - 1) / 2; | |
_addMixedM(Q, [PREC[pIdx][0], PREC[pIdx][1]]); | |
} | |
} | |
} | |
} | |
contract owned { | |
address public owner; | |
/* Initialise contract creator as owner */ | |
function owned() { | |
owner = msg.sender; | |
} | |
/* Function to dictate that only the designated owner can call a function */ | |
modifier onlyOwner { | |
if(owner != msg.sender) throw; | |
_; | |
} | |
/* Transfer ownership of this contract to someone else */ | |
function transferOwnership(address newOwner) onlyOwner() { | |
owner = newOwner; | |
} | |
} | |
/* | |
* @title AnonymousVoting | |
* Open Vote Network | |
* A self-talling protocol that supports voter privacy. | |
* | |
* Author: Patrick McCorry | |
*/ | |
contract AnonymousVoting is owned { | |
// Modulus for public keys | |
uint constant pp = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; | |
// Base point (generator) G | |
uint constant Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; | |
uint constant Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8; | |
// Modulus for private keys (sub-group) | |
uint constant nn = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; | |
uint[2] G; | |
//Every address has an index | |
//This makes looping in the program easier. | |
address[] public addresses; | |
mapping (address => uint) public addressid; // Address to Counter | |
mapping (uint => Voter) public voters; | |
mapping (address => bool) public eligible; // White list of addresses allowed to vote | |
mapping (address => bool) public registered; // Address registered? | |
mapping (address => bool) public votecast; // Address voted? | |
mapping (address => bool) public commitment; // Have we received their commitment? | |
mapping (address => uint) public refunds; // Have we received their commitment? | |
struct Voter { | |
address addr; | |
uint[2] registeredkey; | |
uint[2] reconstructedkey; | |
bytes32 commitment; | |
uint[2] vote; | |
} | |
// Work around function to fetch details about a voter | |
function getVoter() returns (uint[2] _registeredkey, uint[2] _reconstructedkey, bytes32 _commitment){ | |
uint index = addressid[msg.sender]; | |
_registeredkey = voters[index].registeredkey; | |
_reconstructedkey = voters[index].reconstructedkey; | |
_commitment = voters[index].commitment; | |
} | |
// List of timers that each phase MUST end by an explicit time in UNIX timestamp. | |
// Ethereum works in SECONDS. Not milliseconds. | |
uint public finishSignupPhase; // Election Authority to transition to next phase. | |
uint public endSignupPhase; // Election Authority does not transition to next phase by this time. | |
uint public endCommitmentPhase; // Voters have not sent their commitments in by this time. | |
uint public endVotingPhase; // Voters have not submitted their vote by this stage. | |
uint public endRefundPhase; // Voters must claim their refund by this stage. | |
uint public totalregistered; //Total number of participants that have submited a voting key | |
uint public totaleligible; | |
uint public totalcommitted; | |
uint public totalvoted; | |
uint public totalrefunded; | |
uint public totaltorefund; | |
string public question; | |
uint[2] public finaltally; // Final tally | |
bool public commitmentphase; // OPTIONAL phase. | |
uint public depositrequired; | |
uint public gap; // Minimum amount of time between time stamps. | |
address public charity; | |
// TODO: Why cant election authority receive the spoils? | |
uint public lostdeposit; // This money is collected from non active voters... | |
enum State { SETUP, SIGNUP, COMMITMENT, VOTE, FINISHED } | |
State public state; | |
modifier inState(State s) { | |
if(state != s) { | |
throw; | |
} | |
_; | |
} | |
// 2 round anonymous voting protocol | |
// TODO: Right now due to gas limits there is an upper limit | |
// on the number of participants that we can have voting... | |
// I need to split the functions up... so if they cannot | |
// finish their entire workload in 1 transaction, then | |
// it does the maximum. This way we can chain transactions | |
// to complete the job... | |
function AnonymousVoting(uint _gap, address _charity) { | |
G[0] = Gx; | |
G[1] = Gy; | |
state = State.SETUP; | |
question = "No question set"; | |
gap = _gap; // Minimum gap period between stages | |
charity = _charity; | |
} | |
// Owner of contract sets a whitelist of addresses that are eligible to vote. | |
function setEligible(address[] addr) onlyOwner { | |
// We can only handle up 50 people at the moment. | |
if(totaleligible > 50) { | |
throw; | |
} | |
// Sign up the addresses | |
for(uint i=0; i<addr.length; i++) { | |
if(!eligible[addr[i]]) { | |
eligible[addr[i]] = true; | |
addresses.push(addr[i]); | |
totaleligible += 1; | |
} | |
} | |
} | |
// Owner of contract declares that eligible addresses begin round 1 of the protocol | |
// Time is the number of 'blocks' we must wait until we can move onto round 2. | |
function beginSignUp(string _question, bool enableCommitmentPhase, uint _finishSignupPhase, uint _endSignupPhase, uint _endCommitmentPhase, uint _endVotingPhase, uint _endRefundPhase, uint _depositrequired) inState(State.SETUP) onlyOwner payable returns (bool){ | |
// We have lots of timers. let's explain each one | |
// _finishSignUpPhase - Voters should be signed up before this timer | |
// Voter is refunded if any of the timers expire: | |
// _endSignUpPhase - Election Authority never finished sign up phase | |
// _endCommitmentPhase - One or more voters did not send their commitments in time | |
// _endVotingPhase - One or more voters did not send their votes in time | |
// _endRefundPhase - Provide time for voters to get their money back. | |
// Why is there no endTally? Because anyone can call it! | |
// Represented in UNIX time... | |
// TODO: Set to block timestamp... | |
// TODO: Enforce gap to be at least 1 hour.. may break unit testing | |
// Make sure 3 people are at least eligible to vote.. | |
// Deposit can be zero or more WEI | |
if(_finishSignupPhase > 0 + gap && addresses.length >= 3 && _depositrequired >= 0) { | |
// Ensure each time phase finishes in the future... | |
// Ensure there is a gap of 'x time' between each phase. | |
if(_endSignupPhase-gap < _finishSignupPhase) { | |
return false; | |
} | |
// We need to check Commitment timestamps if phase is enabled. | |
if(enableCommitmentPhase) { | |
// Make sure there is a gap between 'end of registration' and 'end of commitment' phases. | |
if(_endCommitmentPhase-gap < _endSignupPhase) { | |
return false; | |
} | |
// Make sure there is a gap between 'end of commitment' and 'end of vote' phases. | |
if(_endVotingPhase-gap < _endCommitmentPhase) { | |
return false; | |
} | |
} else { | |
// We have no commitment phase. | |
// Make sure there is a gap between 'end of registration' and 'end of vote' phases. | |
if(_endVotingPhase-gap < _endSignupPhase) { | |
return false; | |
} | |
} | |
// Provide time for people to get a refund once the voting phase has ended. | |
if(_endRefundPhase-gap < _endVotingPhase) { | |
return false; | |
} | |
// Require Election Authority to deposit ether. | |
if(msg.value != _depositrequired) { | |
return false; | |
} | |
// Store the election authority's deposit | |
// Note: This deposit is only lost if the | |
// election authority does not begin the election | |
// or call the tally function before the timers expire. | |
refunds[msg.sender] = msg.value; | |
// All time stamps are reasonable. | |
// We can now begin the signup phase. | |
state = State.SIGNUP; | |
// All timestamps should be in UNIX.. | |
finishSignupPhase = _finishSignupPhase; | |
endSignupPhase = _endSignupPhase; | |
endCommitmentPhase = _endCommitmentPhase; | |
endVotingPhase = _endVotingPhase; | |
endRefundPhase = _endRefundPhase; | |
question = _question; | |
commitmentphase = enableCommitmentPhase; | |
depositrequired = _depositrequired; // Deposit required from all voters | |
return true; | |
} | |
return false; | |
} | |
// This function determines if one of the deadlines have been missed | |
// If a deadline has been missed - then we finish the election, | |
// and allocate refunds to the correct people depending on the situation. | |
function deadlinePassed() returns (bool){ | |
uint refund = 0; | |
// Has the Election Authority missed the signup deadline? | |
// Election Authority will forfeit his deposit. | |
if(state == State.SIGNUP && block.timestamp > endSignupPhase) { | |
// Nothing to do. All voters are refunded. | |
state = State.FINISHED; | |
totaltorefund = totalregistered; | |
// Election Authority forfeits his deposit... | |
// If 3 or more voters had signed up... | |
if(addresses.length >= 3) { | |
// Election Authority forfeits deposit | |
refund = refunds[owner]; | |
refunds[owner] = 0; | |
lostdeposit = lostdeposit + refund; | |
} | |
return true; | |
} | |
// Has a voter failed to send their commitment? | |
// Election Authority DOES NOT forgeit his deposit. | |
if(state == State.COMMITMENT && block.timestamp > endCommitmentPhase) { | |
// Check which voters have not sent their commitment | |
for(uint i=0; i<totalregistered; i++) { | |
// Voters forfeit their deposit if failed to send a commitment | |
if(!commitment[voters[i].addr]) { | |
refund = refunds[voters[i].addr]; | |
refunds[voters[i].addr] = 0; | |
lostdeposit = lostdeposit + refund; | |
} else { | |
// We will need to refund this person. | |
totaltorefund = totaltorefund + 1; | |
} | |
} | |
state = State.FINISHED; | |
return true; | |
} | |
// Has a voter failed to send in their vote? | |
// Eletion Authority does NOT forfeit his deposit. | |
if(state == State.VOTE && block.timestamp > endVotingPhase) { | |
// Check which voters have not cast their vote | |
for(i=0; i<totalregistered; i++) { | |
// Voter forfeits deposit if they have not voted. | |
if(!votecast[voters[i].addr]) { | |
refund = refunds[voters[i].addr]; | |
refunds[voters[i].addr] = 0; | |
lostdeposit = lostdeposit + refund; | |
} else { | |
// Lets make sure refund has not already been issued... | |
if(refunds[voters[i].addr] > 0) { | |
// We will need to refund this person. | |
totaltorefund = totaltorefund + 1; | |
} | |
} | |
} | |
state = State.FINISHED; | |
return true; | |
} | |
// Has the deadline passed for voters to claim their refund? | |
// Only owner can call. Owner must be refunded (or forfeited). | |
// Refund period is over or everyone has already been refunded. | |
if(state == State.FINISHED && msg.sender == owner && refunds[owner] == 0 && (block.timestamp > endRefundPhase || totaltorefund == totalrefunded)) { | |
// Collect all unclaimed refunds. We will send it to charity. | |
for(i=0; i<totalregistered; i++) { | |
refund = refunds[voters[i].addr]; | |
refunds[voters[i].addr] = 0; | |
lostdeposit = lostdeposit + refund; | |
} | |
uint[2] memory empty; | |
for(i=0; i<addresses.length; i++) { | |
address addr = addresses[i]; | |
eligible[addr] = false; // No longer eligible | |
registered[addr] = false; // Remove voting registration | |
voters[i] = Voter({addr: 0, registeredkey: empty, reconstructedkey: empty, vote: empty, commitment: 0}); | |
addressid[addr] = 0; // Remove index | |
votecast[addr] = false; // Remove that vote was cast | |
commitment[addr] = false; | |
} | |
// Reset timers. | |
finishSignupPhase = 0; | |
endSignupPhase = 0; | |
endCommitmentPhase = 0; | |
endVotingPhase = 0; | |
endRefundPhase = 0; | |
delete addresses; | |
// Keep track of voter activity | |
totalregistered = 0; | |
totaleligible = 0; | |
totalcommitted = 0; | |
totalvoted = 0; | |
// General values that need reset | |
question = "No question set"; | |
finaltally[0] = 0; | |
finaltally[1] = 0; | |
commitmentphase = false; | |
depositrequired = 0; | |
totalrefunded = 0; | |
totaltorefund = 0; | |
state = State.SETUP; | |
return true; | |
} | |
// No deadlines have passed... | |
return false; | |
} | |
// Called by participants to register their voting public key | |
// Participant mut be eligible, and can only register the first key sent key. | |
function register(uint[2] xG, uint[3] vG, uint r) inState(State.SIGNUP) payable returns (bool) { | |
// HARD DEADLINE | |
if(block.timestamp > finishSignupPhase) { | |
throw; // throw returns the voter's ether, but exhausts their gas. | |
} | |
// Make sure the ether being deposited matches what we expect. | |
if(msg.value != depositrequired) { | |
return false; | |
} | |
// Only white-listed addresses can vote | |
if(eligible[msg.sender]) { | |
if(verifyZKP(xG,r,vG) && !registered[msg.sender]) { | |
// Store deposit | |
refunds[msg.sender] = msg.value; | |
// Update voter's registration | |
uint[2] memory empty; | |
addressid[msg.sender] = totalregistered; | |
voters[totalregistered] = Voter({addr: msg.sender, registeredkey: xG, reconstructedkey: empty, vote: empty, commitment: 0}); | |
registered[msg.sender] = true; | |
totalregistered += 1; | |
return true; | |
} | |
} | |
return false; | |
} | |
// Timer has expired - we want to start computing the reconstructed keys | |
function finishRegistrationPhase() inState(State.SIGNUP) onlyOwner returns(bool) { | |
// Make sure at least 3 people have signed up... | |
if(totalregistered < 3) { | |
return; | |
} | |
// We can only compute the public keys once participants | |
// have been given an opportunity to register their | |
// voting public key. | |
if(block.timestamp < finishSignupPhase) { | |
return; | |
} | |
// Election Authority has a deadline to begin election | |
if(block.timestamp > endSignupPhase) { | |
return; | |
} | |
uint[2] memory temp; | |
uint[3] memory yG; | |
uint[3] memory beforei; | |
uint[3] memory afteri; | |
// Step 1 is to compute the index 1 reconstructed key | |
afteri[0] = voters[1].registeredkey[0]; | |
afteri[1] = voters[1].registeredkey[1]; | |
afteri[2] = 1; | |
for(uint i=2; i<totalregistered; i++) { | |
Secp256k1._addMixedM(afteri, voters[i].registeredkey); | |
} | |
ECCMath.toZ1(afteri,pp); | |
voters[0].reconstructedkey[0] = afteri[0]; | |
voters[0].reconstructedkey[1] = pp - afteri[1]; | |
// Step 2 is to add to beforei, and subtract from afteri. | |
for(i=1; i<totalregistered; i++) { | |
if(i==1) { | |
beforei[0] = voters[0].registeredkey[0]; | |
beforei[1] = voters[0].registeredkey[1]; | |
beforei[2] = 1; | |
} else { | |
Secp256k1._addMixedM(beforei, voters[i-1].registeredkey); | |
} | |
// If we have reached the end... just store beforei | |
// Otherwise, we need to compute a key. | |
// Counting from 0 to n-1... | |
if(i==(totalregistered-1)) { | |
ECCMath.toZ1(beforei,pp); | |
voters[i].reconstructedkey[0] = beforei[0]; | |
voters[i].reconstructedkey[1] = beforei[1]; | |
} else { | |
// Subtract 'i' from afteri | |
temp[0] = voters[i].registeredkey[0]; | |
temp[1] = pp - voters[i].registeredkey[1]; | |
// Grab negation of afteri (did not seem to work with Jacob co-ordinates) | |
Secp256k1._addMixedM(afteri,temp); | |
ECCMath.toZ1(afteri,pp); | |
temp[0] = afteri[0]; | |
temp[1] = pp - afteri[1]; | |
// Now we do beforei - afteri... | |
yG = Secp256k1._addMixed(beforei, temp); | |
ECCMath.toZ1(yG,pp); | |
voters[i].reconstructedkey[0] = yG[0]; | |
voters[i].reconstructedkey[1] = yG[1]; | |
} | |
} | |
// We have computed each voter's special voting key. | |
// Now we either enter the commitment phase (option) or voting phase. | |
if(commitmentphase) { | |
state = State.COMMITMENT; | |
} else { | |
state = State.VOTE; | |
} | |
} | |
/* | |
* OPTIONAL STAGE: All voters submit the hash of their vote. | |
* Why? The final voter that submits their vote gets to see the tally result | |
* before anyone else. This provides the voter with an additional advantage | |
* compared to all other voters. To get around this issue; we can force all | |
* voters to commit to their vote in advance.... and votes are only revealed | |
* once all voters have committed. This way the final voter has no additional | |
* advantage as they cannot change their vote depending on the tally. | |
* However... we cannot enforce the pre-image to be a hash, and someone could | |
* a commitment that is not a vote. This will break the election, but you | |
* will be able to determine who did it (and possibly punish them!). | |
*/ | |
function submitCommitment(bytes32 h) inState(State.COMMITMENT) { | |
//All voters have a deadline to send their commitment | |
if(block.timestamp > endCommitmentPhase) { | |
return; | |
} | |
if(!commitment[msg.sender]) { | |
commitment[msg.sender] = true; | |
uint index = addressid[msg.sender]; | |
voters[index].commitment = h; | |
totalcommitted = totalcommitted + 1; | |
// Once we have recorded all commitments... let voters vote! | |
if(totalcommitted == totalregistered) { | |
state = State.VOTE; | |
} | |
} | |
} | |
// Given the 1 out of 2 ZKP - record the users vote! | |
function submitVote(uint[4] params, uint[2] y, uint[2] a1, uint[2] b1, uint[2] a2, uint[2] b2) inState(State.VOTE) returns (bool) { | |
// HARD DEADLINE | |
if(block.timestamp > endVotingPhase) { | |
return; | |
} | |
uint c = addressid[msg.sender]; | |
// Make sure the sender can vote, and hasn't already voted. | |
if(registered[msg.sender] && !votecast[msg.sender]) { | |
// OPTIONAL Phase: Voters need to commit to their vote in advance. | |
// Time to verify if this vote matches the voter's previous commitment. | |
if(commitmentphase) { | |
// Voter has previously committed to the entire zero knowledge proof... | |
bytes32 h = sha3(msg.sender, params, voters[c].registeredkey, voters[c].reconstructedkey, y, a1, b1, a2, b2); | |
// No point verifying the ZKP if it doesn't match the voter's commitment. | |
if(voters[c].commitment != h) { | |
return false; | |
} | |
} | |
// Verify the ZKP for the vote being cast | |
if(verify1outof2ZKP(params, y, a1, b1, a2, b2)) { | |
voters[c].vote[0] = y[0]; | |
voters[c].vote[1] = y[1]; | |
votecast[msg.sender] = true; | |
totalvoted += 1; | |
// Refund the sender their ether.. | |
// Voter has finished their part of the protocol... | |
uint refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
// We can still fail... Safety first. | |
// If failed... voter can call withdrawRefund() | |
// to collect their money once the election has finished. | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return true; | |
} | |
} | |
// Either vote has already been cast, or ZKP verification failed. | |
return false; | |
} | |
// Assuming all votes have been submitted. We can leak the tally. | |
// We assume Election Authority performs this function. It could be anyone. | |
// Election Authority gets deposit upon tallying. | |
// TODO: Anyone can do this function. Perhaps remove refund code - and force Election Authority | |
// to explicit withdraw it? Election cannot reset until he is refunded - so that should be OK | |
function computeTally() inState(State.VOTE) onlyOwner { | |
uint[3] memory temp; | |
uint[2] memory vote; | |
uint refund; | |
// Sum all votes | |
for(uint i=0; i<totalregistered; i++) { | |
// Confirm all votes have been cast... | |
if(!votecast[voters[i].addr]) { | |
throw; | |
} | |
vote = voters[i].vote; | |
if(i==0) { | |
temp[0] = vote[0]; | |
temp[1] = vote[1]; | |
temp[2] = 1; | |
} else { | |
Secp256k1._addMixedM(temp, vote); | |
} | |
} | |
// All votes have been accounted for... | |
// Get tally, and change state to 'Finished' | |
state = State.FINISHED; | |
// All voters should already be refunded! | |
for(i = 0; i<totalregistered; i++) { | |
// Sanity check.. make sure refunds have been issued.. | |
if(refunds[voters[i].addr] > 0) { | |
totaltorefund = totaltorefund + 1; | |
} | |
} | |
// Each vote is represented by a G. | |
// If there are no votes... then it is 0G = (0,0)... | |
if(temp[0] == 0) { | |
finaltally[0] = 0; | |
finaltally[1] = totalregistered; | |
// Election Authority is responsible for calling this.... | |
// He should not fail his own refund... | |
// Make sure tally is computed before refunding... | |
// TODO: Check if this is necessary | |
refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return; | |
} else { | |
// There must be a vote. So lets | |
// start adding 'G' until we | |
// find the result. | |
ECCMath.toZ1(temp,pp); | |
uint[3] memory tempG; | |
tempG[0] = G[0]; | |
tempG[1] = G[1]; | |
tempG[2] = 1; | |
// Start adding 'G' and looking for a match | |
for(i=1; i<=totalregistered; i++) { | |
if(temp[0] == tempG[0]) { | |
finaltally[0] = i; | |
finaltally[1] = totalregistered; | |
// Election Authority is responsible for calling this.... | |
// He should not fail his own refund... | |
// Make sure tally is computed before refunding... | |
// TODO: Check if this is necessary | |
// If it fails - he can use withdrawRefund() | |
// Election cannot be reset until he is refunded. | |
refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return; | |
} | |
// If something bad happens and we cannot find the Tally | |
// Then this 'addition' will be run 1 extra time due to how | |
// we have structured the for loop. | |
// TODO: Does it need fixed? | |
Secp256k1._addMixedM(tempG, G); | |
ECCMath.toZ1(tempG,pp); | |
} | |
// Something bad happened. We should never get here.... | |
// This represents an error message... best telling people | |
// As we cannot recover from it anyway. | |
// TODO: Handle this better.... | |
finaltally[0] = 0; | |
finaltally[1] = 0; | |
// Election Authority is responsible for calling this.... | |
// He should not fail his own refund... | |
// TODO: Check if this is necessary | |
refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return; | |
} | |
} | |
// There are two reasons why we might be in a finished state | |
// 1. The tally has been computed | |
// 2. A deadline has been missed. | |
// In the former; everyone gets a refund. In the latter; only active participants get a refund | |
// We can assume if the deadline has been missed - then refunds has ALREADY been updated to | |
// take that into account. (a transaction is required to indicate a deadline has been missed | |
// and in that transaction - we can penalise the non-active participants. lazy sods!) | |
function withdrawRefund() inState(State.FINISHED){ | |
uint refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} else { | |
// Tell everyone we have issued the refund. | |
// Owner is not included in refund counter. | |
// This is OK - we cannot reset election until | |
// the owner has been refunded... | |
// Counter only concerns voters! | |
if(msg.sender != owner) { | |
totalrefunded = totalrefunded + 1; | |
} | |
} | |
} | |
// Send the lost deposits to a charity. Anyone can call it. | |
// Lost Deposit increments for each failed election. It is only | |
// reset upon sending to the charity! | |
function sendToCharity() { | |
// Only send this money to the owner | |
uint profit = lostdeposit; | |
lostdeposit = 0; | |
// Try to send money | |
if(!charity.send(profit)) { | |
// We failed to send the money. Record it again. | |
lostdeposit = profit; | |
} | |
} | |
// Parameters xG, r where r = v - xc, and vG. | |
// Verify that vG = rG + xcG! | |
function verifyZKP(uint[2] xG, uint r, uint[3] vG) returns (bool){ | |
uint[2] memory G; | |
G[0] = Gx; | |
G[1] = Gy; | |
// Check both keys are on the curve. | |
if(!Secp256k1.isPubKey(xG) || !Secp256k1.isPubKey(vG)) { | |
return false; //Must be on the curve! | |
} | |
// Get c = H(g, g^{x}, g^{v}); | |
bytes32 b_c = sha256(msg.sender, Gx, Gy, xG, vG); | |
uint c = uint(b_c); | |
// Get g^{r}, and g^{xc} | |
uint[3] memory rG = Secp256k1._mul(r, G); | |
uint[3] memory xcG = Secp256k1._mul(c, xG); | |
// Add both points together | |
uint[3] memory rGxcG = Secp256k1._add(rG,xcG); | |
// Convert to Affine Co-ordinates | |
ECCMath.toZ1(rGxcG, pp); | |
// Verify. Do they match? | |
if(rGxcG[0] == vG[0] && rGxcG[1] == vG[1]) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
// We verify that the ZKP is of 0 or 1. | |
function verify1outof2ZKP(uint[4] params, uint[2] y, uint[2] a1, uint[2] b1, uint[2] a2, uint[2] b2) returns (bool) { | |
uint[2] memory temp1; | |
uint[3] memory temp2; | |
uint[3] memory temp3; | |
// Voter Index | |
uint i = addressid[msg.sender]; | |
// We already have them stored... | |
// TODO: Decide if this should be in SubmitVote or here... | |
uint[2] memory yG = voters[i].reconstructedkey; | |
uint[2] memory xG = voters[i].registeredkey; | |
// Make sure we are only dealing with valid public keys! | |
if(!Secp256k1.isPubKey(xG) || !Secp256k1.isPubKey(yG) || !Secp256k1.isPubKey(y) || !Secp256k1.isPubKey(a1) || | |
!Secp256k1.isPubKey(b1) || !Secp256k1.isPubKey(a2) || !Secp256k1.isPubKey(b2)) { | |
return false; | |
} | |
// Does c =? d1 + d2 (mod n) | |
if(uint(sha256(msg.sender, xG, y, a1, b1, a2, b2)) != addmod(params[0],params[1],nn)) { | |
return false; | |
} | |
// a1 =? g^{r1} * x^{d1} | |
temp2 = Secp256k1._mul(params[2], G); | |
temp3 = Secp256k1._add(temp2, Secp256k1._mul(params[0], xG)); | |
ECCMath.toZ1(temp3, pp); | |
if(a1[0] != temp3[0] || a1[1] != temp3[1]) { | |
return false; | |
} | |
//b1 =? h^{r1} * y^{d1} (temp = affine 'y') | |
temp2 = Secp256k1._mul(params[2],yG); | |
temp3 = Secp256k1._add(temp2, Secp256k1._mul(params[0], y)); | |
ECCMath.toZ1(temp3, pp); | |
if(b1[0] != temp3[0] || b1[1] != temp3[1]) { | |
return false; | |
} | |
//a2 =? g^{r2} * x^{d2} | |
temp2 = Secp256k1._mul(params[3],G); | |
temp3 = Secp256k1._add(temp2, Secp256k1._mul(params[1], xG)); | |
ECCMath.toZ1(temp3, pp); | |
if(a2[0] != temp3[0] || a2[1] != temp3[1]) { | |
return false; | |
} | |
// Negate the 'y' co-ordinate of g | |
temp1[0] = G[0]; | |
temp1[1] = pp - G[1]; | |
// get 'y' | |
temp3[0] = y[0]; | |
temp3[1] = y[1]; | |
temp3[2] = 1; | |
// y-g | |
temp2 = Secp256k1._addMixed(temp3,temp1); | |
// Return to affine co-ordinates | |
ECCMath.toZ1(temp2, pp); | |
temp1[0] = temp2[0]; | |
temp1[1] = temp2[1]; | |
// (y-g)^{d2} | |
temp2 = Secp256k1._mul(params[1],temp1); | |
// Now... it is h^{r2} + temp2.. | |
temp3 = Secp256k1._add(Secp256k1._mul(params[3],yG),temp2); | |
// Convert to Affine Co-ordinates | |
ECCMath.toZ1(temp3, pp); | |
// Should all match up. | |
if(b2[0] != temp3[0] || b2[1] != temp3[1]) { | |
return false; | |
} | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.18; | |
contract Test { | |
address owner; | |
uint256 val = 256; | |
address otherContract; | |
constructor () public{ | |
owner = msg.sender; | |
} | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
modifier onlyOtherContract() { | |
require(msg.sender == otherContract); | |
_; | |
} | |
function setOtherContract(address _otherContract) public onlyOwner { | |
otherContract = _otherContract; | |
} | |
function getVal() onlyOtherContract public view returns (uint) { | |
return val; | |
} | |
} | |
contract Other { | |
Test testContract; | |
function setAddress(address _address) public { | |
testContract = Test(_address); | |
} | |
function getVal() constant public returns (uint256) { | |
return testContract.getVal(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.11; | |
contract Purchase { | |
uint public purchaseValue; | |
address public sellerAddress; | |
address public buyerAddress; | |
enum purchaseState { Created, Locked, Inactive } | |
purchaseState public purchasestate; | |
// Make sure that <code data-enlighter-language="generic" class="EnlighterJSRAW">msg.value</code> is an even number. | |
// Division truncates if the number is odd. | |
// Use multiplication to check that it wasn't an odd number. | |
function Purchase() payable { | |
sellerAddress = msg.sender; | |
purchaseValue = msg.value / 2; | |
require((2 * purchaseValue) == msg.value); | |
s | |
} | |
modifier condition(bool _condition) { | |
require(_condition); | |
_; | |
} | |
modifier onlyBuyerAddress() { | |
require(msg.sender == buyerAddress); | |
_; | |
} | |
modifier onlySellerAddress() { | |
require(msg.sender == sellerAddress); | |
_; | |
} | |
modifier inPurchaseState(purchaseState _purchasestate) { | |
require(purchasestate == _purchasestate); | |
_; | |
} | |
event abortedPurchase(); | |
event confirmedPurchase(); | |
event receivedItem(); | |
/// Purchase is aborted and ether is reclaimed. | |
/// May only be called by the seller before | |
/// locking the contract. | |
function abortPurchase() | |
onlySellerAddress | |
inPurchaseState(purchaseState.Created) | |
{ | |
abortedPurchase(); | |
purchasestate = purchaseState.Inactive; | |
sellerAddress.transfer(this.balance); | |
} | |
/// The purchase confirmed as a buyer. | |
/// Transaction includes <code data-enlighter-language="generic" class="EnlighterJSRAW">2 * purchaseValue</code> ether. | |
/// The ether is locked until receivedConfirm | |
/// is called. | |
function purchaseConfirm() | |
inPurchaseState(purchaseState.Created) | |
condition(msg.value == (2 * purchaseValue)) | |
payable | |
{ | |
confirmedPurchase(); | |
buyerAddress = msg.sender; | |
purchasestate = purchaseState.Locked; | |
} | |
/// Confirm that you (the buyerAddress) received the item. | |
/// This will release the locked ether. | |
function receivedConfirm() | |
onlyBuyerAddress | |
inPurchaseState(purchaseState.Locked) | |
{ | |
receivedItem(); | |
// It is crucial to change the purchasestate firsthand since | |
// otherwise, the contracts called using <code data-enlighter-language="generic" class="EnlighterJSRAW">send</code> below | |
// can call in again here. | |
purchasestate = purchaseState.Inactive; | |
// NOTE: this will allow both sellerAddress and the buyerAddress to | |
// block the refund - it is recommended to use the withdraw pattern. | |
buyerAddress.transfer(purchaseValue); | |
sellerAddress.transfer(this.balance); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.7; | |
import "remix_tests.sol"; // this import is automatically injected by Remix. | |
import "./ballot.sol"; | |
contract test3 { | |
Ballot ballotToTest; | |
function beforeAll () { | |
ballotToTest = new Ballot(2); | |
} | |
function checkWinningProposal () public { | |
ballotToTest.vote(1); | |
Assert.equal(ballotToTest.winningProposal(), uint(1), "1 should be the winning proposal"); | |
} | |
function checkWinninProposalWithReturnValue () public constant returns (bool) { | |
return ballotToTest.winningProposal() == 1; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract MyPlate{ | |
uint public price = 1 wei; | |
struct Vehicle{ | |
string plate_id; | |
address owner_address; | |
string chungloai; | |
string characteristics; | |
string ngaycap; | |
uint256 balances; | |
} | |
struct Citizen{ | |
address citizenID; | |
string fName; | |
string lName; | |
string birthDay; | |
string queQuan; | |
string[] plate_ids; | |
} | |
mapping (address => Citizen) citizens; | |
address[] public citizenList; | |
function addCitizen(address _address, string _f, string _l, string _birthDay, string _queQuan) public{ | |
Citizen storage citizen = citizens[_address]; | |
citizen.citizenID=_address; | |
citizen.fName=_f; | |
citizen.lName=_l; | |
citizen.birthDay=_birthDay; | |
citizen.queQuan=_queQuan; | |
citizenList.push(_address) -1; | |
} | |
function getCitizen(address _address) public view returns(address){ | |
return citizens[_address].citizenID; | |
} | |
mapping (string =>Vehicle) vehicles; | |
string[] public vehiclesList; | |
function getPrice() public view returns(uint256){ | |
return price; | |
} | |
function setPrice(uint256 _new_price) public{ | |
if (price>0){ | |
price = _new_price; | |
} | |
else{ | |
revert(); | |
} | |
} | |
function addVehicle(string _plate_id, address _owner_address, string _type, string _charac, string _ngaycap, uint256 _balances) public{ | |
Vehicle storage vehicle = vehicles[_plate_id]; | |
citizens[_owner_address].plate_ids.push(_plate_id) -1; | |
vehicle.plate_id = _plate_id; | |
vehicle.owner_address=_owner_address; | |
vehicle.chungloai=_type; | |
vehicle.characteristics=_charac; | |
vehicle.ngaycap=_ngaycap; | |
vehicle.balances=_balances; | |
vehiclesList.push(_plate_id) -1; | |
} | |
function getVehicle(string _plate_id) view public returns (address, string, string, string, uint256){ | |
return (vehicles[_plate_id].owner_address, vehicles[_plate_id].chungloai, vehicles[_plate_id].characteristics, vehicles[_plate_id].ngaycap, vehicles[_plate_id].balances); | |
} | |
function addCoin(string _plate_id, uint256 amount) payable public{ | |
if (msg.value !=amount*price){ | |
revert(); | |
} | |
vehicles[_plate_id].balances+= amount; | |
} | |
function verifyVehicle(string _plate_id) public returns (bool result){ | |
if (vehicles[_plate_id].balances<price) return false; | |
else { | |
vehicles[_plate_id].balances=vehicles[_plate_id].balances - price; | |
return true; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract BotManagement{ | |
struct Account{ | |
address owner; | |
uint256 balance; | |
} | |
mapping (address => Account) accounts; | |
struct Bot{ | |
address owner; | |
int status; //0: deactive, 1: active; | |
} | |
mapping( address => Bot) Bots; | |
struct Permission{ | |
address owner; | |
int256 typePermis; | |
//0. Bị thu hồi các quyền. | |
//1. Cấp quyền cho các account khác và các quyền còn lại. | |
//2. Chỉ có quyền đăng ký phương tiện, ko có quyền cấp quyền cho account khác. | |
} | |
mapping (address => Permission) permissionList; | |
function checkPermission() public view returns(int256){ | |
if (permissionList[msg.sender].owner == msg.sender) { | |
return -1; | |
} | |
else{ | |
return permissionList[msg.sender].typePermis; | |
} | |
} | |
function addPermission(address _address, int256 _type) public returns(bool){ | |
if (checkPermission() == 1) { | |
permissionList[_address].owner = _address; | |
permissionList[_address].typePermis = _type; | |
return true; | |
} | |
return false; | |
} | |
function addBot(address _address) public returns(bool){ | |
if (checkPermission()==1){ | |
Bot storage tmp_bot = Bots[_address]; | |
tmp_bot.owner=_address; | |
tmp_bot.status= 1; | |
return true; | |
} | |
return false; | |
} | |
function addAccount(address _address) public returns(bool){ | |
if (checkPermission()==1){ | |
Account storage tmp_account = accounts[_address]; | |
tmp_account.owner = _address; | |
return true; | |
} | |
return false; | |
} | |
function addCoin() public payable returns(bool){ | |
if (accounts[msg.sender].owner==msg.sender){ | |
accounts[msg.sender].balance+=msg.value; | |
return true; | |
} | |
return false; | |
} | |
//function verifyVehicle(string _plate_id, string _etag_id) public returns (bool){ | |
// | |
//} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.18; | |
contract Deployed { | |
uint public a = 1; | |
function setA(uint _a) public returns (uint) { | |
a = _a; | |
return a; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract Vehicles{ | |
constructor(address _address) public{ | |
permissionList[_address].owner = _address; | |
permissionList[_address].typePermis = 1; | |
} | |
function getOwner() public view returns (address){ | |
return msg.sender; | |
} | |
struct Permission{ | |
address owner; | |
int256 typePermis; | |
//0. Bị thu hồi các quyền. | |
//1. Cấp quyền cho các account khác và các quyền còn lại. | |
//2. Chỉ có quyền đăng ký phương tiện, ko có quyền cấp quyền cho account khác. | |
} | |
mapping (address => Permission) permissionList; | |
struct Person { | |
address owner; | |
string yearOfRegis; | |
string etag_id; | |
} | |
struct Vehicle{ | |
string plate_id; | |
mapping (uint256 => Person) persons; | |
uint256 lenghtPerson; | |
string name; | |
string typeOfVehicle; | |
string color; | |
string yearOfPro; | |
string charactic; | |
string manufac; | |
string serial; | |
string status; //active, deactive, stolen. | |
} | |
mapping (string => Vehicle) vehicles; | |
string[] public vehiclesList; | |
function checkOwner(address _owner, string _plate_id) public view returns(bool){ | |
if (vehicles[_plate_id].persons[vehicles[_plate_id].lenghtPerson -1 ].owner != _owner){ | |
return (false); | |
} | |
else{ | |
return (true); | |
} | |
} | |
function checkPermission() public view returns(int256){ | |
if (permissionList[msg.sender].owner == msg.sender) { | |
return -1; | |
} | |
else{ | |
return permissionList[msg.sender].typePermis; | |
} | |
} | |
function addPermission(address _address, int256 _type) public returns(bool){ | |
if (checkPermission() == 1) { | |
permissionList[_address].owner = _address; | |
permissionList[_address].typePermis = _type; | |
return true; | |
} | |
return false; | |
} | |
function addVehicle(address _owner, string _plate_id, string _name, string _type, string _color, string _yearOfPro, string _yearOfRegis, string _charac, string _manufac, string _serial, string _etag_id) public returns (bool){ | |
if (checkPermission()<1){ | |
return false; | |
} | |
else{ | |
Vehicle storage vehicle = vehicles[_plate_id]; | |
vehicle.lenghtPerson = 0; | |
Person storage p = vehicle.persons[vehicle.lenghtPerson] ; | |
p.owner = _owner; | |
p.yearOfRegis= _yearOfRegis; | |
p.etag_id = _etag_id; | |
vehicle.plate_id = _plate_id; | |
vehicle.name = _name; | |
vehicle.typeOfVehicle = _type; | |
vehicle.color = _color; | |
vehicle.yearOfPro = _yearOfPro; | |
vehicle.charactic = _charac; | |
vehicle.manufac = _manufac; | |
vehicle.serial = _serial; | |
vehicle.status = "active"; | |
vehicle.lenghtPerson++; | |
vehiclesList.push(_plate_id) -1; | |
return true; | |
} | |
} | |
function changeOwner(string _plate_id, address _owner, address _new_owner, string _yearOfRegis, string _etag_id) public returns (bool){ | |
if (checkPermission()<1){ | |
return false; | |
} | |
if (!checkOwner(_owner, _plate_id)){ | |
return false; | |
} | |
else{ | |
Person storage p = vehicles[_plate_id].persons[vehicles[_plate_id].lenghtPerson] ; | |
p.owner = _new_owner; | |
p.yearOfRegis = _yearOfRegis; | |
p.etag_id = _etag_id; | |
vehicles[_plate_id].lenghtPerson ++; | |
return true; | |
} | |
} | |
function renewEtagID(string _plate_id, address _owner) public view returns(bool, string){ | |
if (checkPermission()<1){ | |
return (false, ""); | |
} | |
if (!checkOwner(_owner, _plate_id)){ | |
return (false, ""); | |
} | |
else{ | |
string storage _etag_id = vehicles[_plate_id].persons[vehicles[_plate_id].lenghtPerson -1 ].etag_id; | |
return (true, _etag_id); | |
} | |
} | |
function changeStatus(string _plate_id, address _owner, string _status) public returns(bool){ | |
if (checkPermission()<1){ | |
return false; | |
} | |
if (!checkOwner(_owner, _plate_id)){ | |
return false; | |
} | |
else{ | |
vehicles[_plate_id].status = _status; | |
return (true); | |
} | |
} | |
function getFixedInfo(string _plate_id) view public returns (string, string, string, string, string) { | |
return(vehicles[_plate_id].name, vehicles[_plate_id].typeOfVehicle, vehicles[_plate_id].yearOfPro, vehicles[_plate_id].manufac, vehicles[_plate_id].serial); | |
} | |
function getDynamicInfo(string _plate_id) view public returns (address, string, string, string, string){ | |
address _owner = vehicles[_plate_id].persons[vehicles[_plate_id].lenghtPerson].owner; | |
string storage _yearOfRegis = vehicles[_plate_id].persons[vehicles[_plate_id].lenghtPerson].yearOfRegis; | |
return (_owner, _yearOfRegis , vehicles[_plate_id].color, vehicles[_plate_id].charactic, vehicles[_plate_id].status); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.18; | |
// ---------------------------------------------------------------------------- | |
// '0Fucks' token contract | |
// | |
// Deployed to : 0x5A86f0cafD4ef3ba4f0344C138afcC84bd1ED222 | |
// Symbol : 0FUCKS | |
// Name : 0 Fucks Token | |
// Total supply: 100000000 | |
// Decimals : 18 | |
// | |
// Enjoy. | |
// | |
// (c) by Moritz Neto with BokkyPooBah / Bok Consulting Pty Ltd Au 2017. The MIT Licence. | |
// ---------------------------------------------------------------------------- | |
// ---------------------------------------------------------------------------- | |
// Safe maths | |
// ---------------------------------------------------------------------------- | |
contract SafeMath { | |
function safeAdd(uint a, uint b) public pure returns (uint c) { | |
c = a + b; | |
require(c >= a); | |
} | |
function safeSub(uint a, uint b) public pure returns (uint c) { | |
require(b <= a); | |
c = a - b; | |
} | |
function safeMul(uint a, uint b) public pure returns (uint c) { | |
c = a * b; | |
require(a == 0 || c / a == b); | |
} | |
function safeDiv(uint a, uint b) public pure returns (uint c) { | |
require(b > 0); | |
c = a / b; | |
} | |
} | |
// ---------------------------------------------------------------------------- | |
// ERC Token Standard #20 Interface | |
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md | |
// ---------------------------------------------------------------------------- | |
contract ERC20Interface { | |
function totalSupply() public constant returns (uint); | |
function balanceOf(address tokenOwner) public constant returns (uint balance); | |
function allowance(address tokenOwner, address spender) public constant returns (uint remaining); | |
function transfer(address to, uint tokens) public returns (bool success); | |
function approve(address spender, uint tokens) public returns (bool success); | |
function transferFrom(address from, address to, uint tokens) public returns (bool success); | |
event Transfer(address indexed from, address indexed to, uint tokens); | |
event Approval(address indexed tokenOwner, address indexed spender, uint tokens); | |
} | |
// ---------------------------------------------------------------------------- | |
// Contract function to receive approval and execute function in one call | |
// | |
// Borrowed from MiniMeToken | |
// ---------------------------------------------------------------------------- | |
contract ApproveAndCallFallBack { | |
function receiveApproval(address from, uint256 tokens, address token, bytes data) public; | |
} | |
// ---------------------------------------------------------------------------- | |
// Owned contract | |
// ---------------------------------------------------------------------------- | |
contract Owned { | |
address public owner; | |
address public newOwner; | |
event OwnershipTransferred(address indexed _from, address indexed _to); | |
function Owned() public { | |
owner = msg.sender; | |
} | |
modifier onlyOwner { | |
require(msg.sender == owner); | |
_; | |
} | |
function transferOwnership(address _newOwner) public onlyOwner { | |
newOwner = _newOwner; | |
} | |
function acceptOwnership() public { | |
require(msg.sender == newOwner); | |
OwnershipTransferred(owner, newOwner); | |
owner = newOwner; | |
newOwner = address(0); | |
} | |
} | |
// ---------------------------------------------------------------------------- | |
// ERC20 Token, with the addition of symbol, name and decimals and assisted | |
// token transfers | |
// ---------------------------------------------------------------------------- | |
contract BBT is ERC20Interface, Owned, SafeMath { | |
string public symbol; | |
string public name; | |
uint8 public decimals; | |
uint public _totalSupply; | |
mapping(address => uint) balances; | |
mapping(address => mapping(address => uint)) allowed; | |
// ------------------------------------------------------------------------ | |
// Constructor | |
// ------------------------------------------------------------------------ | |
function BBT() public { | |
symbol = "BBT"; | |
name = "TU NGONG TOKEN"; | |
decimals = 18; | |
_totalSupply = 100000000000000000000000000; | |
balances[0xcA4dbd935Ade806B74B94E1FfE706D0eec770174] = _totalSupply; | |
Transfer(address(0), 0xcA4dbd935Ade806B74B94E1FfE706D0eec770174, _totalSupply); | |
} | |
// ------------------------------------------------------------------------ | |
// Total supply | |
// ------------------------------------------------------------------------ | |
function totalSupply() public constant returns (uint) { | |
return _totalSupply - balances[address(0)]; | |
} | |
// ------------------------------------------------------------------------ | |
// Get the token balance for account tokenOwner | |
// ------------------------------------------------------------------------ | |
function balanceOf(address tokenOwner) public constant returns (uint balance) { | |
return balances[tokenOwner]; | |
} | |
// ------------------------------------------------------------------------ | |
// Transfer the balance from token owner's account to to account | |
// - Owner's account must have sufficient balance to transfer | |
// - 0 value transfers are allowed | |
// ------------------------------------------------------------------------ | |
function transfer(address to, uint tokens) public returns (bool success) { | |
balances[msg.sender] = safeSub(balances[msg.sender], tokens); | |
balances[to] = safeAdd(balances[to], tokens); | |
Transfer(msg.sender, to, tokens); | |
return true; | |
} | |
// ------------------------------------------------------------------------ | |
// Token owner can approve for spender to transferFrom(...) tokens | |
// from the token owner's account | |
// | |
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md | |
// recommends that there are no checks for the approval double-spend attack | |
// as this should be implemented in user interfaces | |
// ------------------------------------------------------------------------ | |
function approve(address spender, uint tokens) public returns (bool success) { | |
allowed[msg.sender][spender] = tokens; | |
Approval(msg.sender, spender, tokens); | |
return true; | |
} | |
// ------------------------------------------------------------------------ | |
// Transfer tokens from the from account to the to account | |
// | |
// The calling account must already have sufficient tokens approve(...)-d | |
// for spending from the from account and | |
// - From account must have sufficient balance to transfer | |
// - Spender must have sufficient allowance to transfer | |
// - 0 value transfers are allowed | |
// ------------------------------------------------------------------------ | |
function transferFrom(address from, address to, uint tokens) public returns (bool success) { | |
balances[from] = safeSub(balances[from], tokens); | |
allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens); | |
balances[to] = safeAdd(balances[to], tokens); | |
Transfer(from, to, tokens); | |
return true; | |
} | |
// ------------------------------------------------------------------------ | |
// Returns the amount of tokens approved by the owner that can be | |
// transferred to the spender's account | |
// ------------------------------------------------------------------------ | |
function allowance(address tokenOwner, address spender) public constant returns (uint remaining) { | |
return allowed[tokenOwner][spender]; | |
} | |
// ------------------------------------------------------------------------ | |
// Token owner can approve for spender to transferFrom(...) tokens | |
// from the token owner's account. The spender contract function | |
// receiveApproval(...) is then executed | |
// ------------------------------------------------------------------------ | |
function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) { | |
allowed[msg.sender][spender] = tokens; | |
Approval(msg.sender, spender, tokens); | |
ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data); | |
return true; | |
} | |
// ------------------------------------------------------------------------ | |
// Don't accept ETH | |
// ------------------------------------------------------------------------ | |
function () public payable { | |
revert(); | |
} | |
// ------------------------------------------------------------------------ | |
// Owner can transfer out any accidentally sent ERC20 tokens | |
// ------------------------------------------------------------------------ | |
function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) { | |
return ERC20Interface(tokenAddress).transfer(owner, tokens); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.18; | |
contract ExistingVehicle { | |
address dc; | |
function ExistingWithoutABI(address _t) public { | |
dc = _t; | |
} | |
function getVehicle(string _plate_id) public returns(bool success){ | |
address vehicleaddresss =0xdaf1dfbc65528a9a137e4fd632473cb4f1b7bb19; | |
require(vehicleaddresss.call(bytes4(keccak256("getDynamicInfo(string)")),_plate_id)); | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.18; | |
contract Test { | |
address owner; | |
uint256 val = 256; | |
address otherContract; | |
constructor() public{ | |
owner = msg.sender; | |
} | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
modifier onlyOtherContract() { | |
require(msg.sender == otherContract); | |
_; | |
} | |
function setOtherContract(address _otherContract) onlyOwner { | |
otherContract = _otherContract; | |
} | |
function getVal() onlyOtherContract returns (uint) { | |
return val; | |
} | |
} | |
contract Other { | |
Test testContract; | |
function setAddress(address _address) { | |
testContract = Test(_address); | |
} | |
function getVal() constant public returns (uint256) { | |
return testContract.getVal(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.3; | |
/** | |
* @title ECCMath | |
* | |
* Functions for working with integers, curve-points, etc. | |
* | |
* @author Andreas Olofsson ([email protected]) | |
*/ | |
library ECCMath { | |
/// @dev Modular inverse of a (mod p) using euclid. | |
/// "a" and "p" must be co-prime. | |
/// @param a The number. | |
/// @param p The mmodulus. | |
/// @return x such that ax = 1 (mod p) | |
function invmod(uint a, uint p) internal constant returns (uint) { | |
if (a == 0 || a == p || p == 0) | |
throw; | |
if (a > p) | |
a = a % p; | |
int t1; | |
int t2 = 1; | |
uint r1 = p; | |
uint r2 = a; | |
uint q; | |
while (r2 != 0) { | |
q = r1 / r2; | |
(t1, t2, r1, r2) = (t2, t1 - int(q) * t2, r2, r1 - q * r2); | |
} | |
if (t1 < 0) | |
return (p - uint(-t1)); | |
return uint(t1); | |
} | |
/// @dev Modular exponentiation, b^e % m | |
/// Basically the same as can be found here: | |
/// https://github.com/ethereum/serpent/blob/develop/examples/ecc/modexp.se | |
/// @param b The base. | |
/// @param e The exponent. | |
/// @param m The modulus. | |
/// @return x such that x = b**e (mod m) | |
function expmod(uint b, uint e, uint m) internal constant returns (uint r) { | |
if (b == 0) | |
return 0; | |
if (e == 0) | |
return 1; | |
if (m == 0) | |
throw; | |
r = 1; | |
uint bit = 2 ** 255; | |
bit = bit; | |
assembly { | |
loop: | |
jumpi(end, iszero(bit)) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, bit)))), m) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, div(bit, 2))))), m) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, div(bit, 4))))), m) | |
r := mulmod(mulmod(r, r, m), exp(b, iszero(iszero(and(e, div(bit, 8))))), m) | |
bit := div(bit, 16) | |
jump(loop) | |
end: | |
} | |
} | |
/// @dev Converts a point (Px, Py, Pz) expressed in Jacobian coordinates to (Px", Py", 1). | |
/// Mutates P. | |
/// @param P The point. | |
/// @param zInv The modular inverse of "Pz". | |
/// @param z2Inv The square of zInv | |
/// @param prime The prime modulus. | |
/// @return (Px", Py", 1) | |
function toZ1(uint[3] memory P, uint zInv, uint z2Inv, uint prime) internal constant { | |
P[0] = mulmod(P[0], z2Inv, prime); | |
P[1] = mulmod(P[1], mulmod(zInv, z2Inv, prime), prime); | |
P[2] = 1; | |
} | |
/// @dev See _toZ1(uint[3], uint, uint). | |
/// Warning: Computes a modular inverse. | |
/// @param PJ The point. | |
/// @param prime The prime modulus. | |
/// @return (Px", Py", 1) | |
function toZ1(uint[3] PJ, uint prime) internal constant { | |
uint zInv = invmod(PJ[2], prime); | |
uint zInv2 = mulmod(zInv, zInv, prime); | |
PJ[0] = mulmod(PJ[0], zInv2, prime); | |
PJ[1] = mulmod(PJ[1], mulmod(zInv, zInv2, prime), prime); | |
PJ[2] = 1; | |
} | |
} | |
library Secp256k1 { | |
// TODO separate curve from crypto primitives? | |
// Field size | |
uint constant pp = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; | |
// Base point (generator) G | |
uint constant Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; | |
uint constant Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8; | |
// Order of G | |
uint constant nn = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; | |
// Cofactor | |
// uint constant hh = 1; | |
// Maximum value of s | |
uint constant lowSmax = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0; | |
// For later | |
// uint constant lambda = "0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72"; | |
// uint constant beta = "0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"; | |
/// @dev See Curve.onCurve | |
function onCurve(uint[2] P) internal constant returns (bool) { | |
uint p = pp; | |
if (0 == P[0] || P[0] == p || 0 == P[1] || P[1] == p) | |
return false; | |
uint LHS = mulmod(P[1], P[1], p); | |
uint RHS = addmod(mulmod(mulmod(P[0], P[0], p), P[0], p), 7, p); | |
return LHS == RHS; | |
} | |
/// @dev See Curve.isPubKey | |
function isPubKey(uint[2] memory P) internal constant returns (bool isPK) { | |
isPK = onCurve(P); | |
} | |
/// @dev See Curve.isPubKey | |
// TODO: We assume we are given affine co-ordinates for now | |
function isPubKey(uint[3] memory P) internal constant returns (bool isPK) { | |
uint[2] memory a_P; | |
a_P[0] = P[0]; | |
a_P[1] = P[1]; | |
isPK = onCurve(a_P); | |
} | |
/// @dev See Curve.validateSignature | |
function validateSignature(bytes32 message, uint[2] rs, uint[2] Q) internal constant returns (bool) { | |
uint n = nn; | |
uint p = pp; | |
if(rs[0] == 0 || rs[0] >= n || rs[1] == 0 || rs[1] > lowSmax) | |
return false; | |
if (!isPubKey(Q)) | |
return false; | |
uint sInv = ECCMath.invmod(rs[1], n); | |
uint[3] memory u1G = _mul(mulmod(uint(message), sInv, n), [Gx, Gy]); | |
uint[3] memory u2Q = _mul(mulmod(rs[0], sInv, n), Q); | |
uint[3] memory P = _add(u1G, u2Q); | |
if (P[2] == 0) | |
return false; | |
uint Px = ECCMath.invmod(P[2], p); // need Px/Pz^2 | |
Px = mulmod(P[0], mulmod(Px, Px, p), p); | |
return Px % n == rs[0]; | |
} | |
/// @dev See Curve.compress | |
function compress(uint[2] P) internal constant returns (uint8 yBit, uint x) { | |
x = P[0]; | |
yBit = P[1] & 1 == 1 ? 1 : 0; | |
} | |
/// @dev See Curve.decompress | |
function decompress(uint8 yBit, uint x) internal constant returns (uint[2] P) { | |
uint p = pp; | |
var y2 = addmod(mulmod(x, mulmod(x, x, p), p), 7, p); | |
var y_ = ECCMath.expmod(y2, (p + 1) / 4, p); | |
uint cmp = yBit ^ y_ & 1; | |
P[0] = x; | |
P[1] = (cmp == 0) ? y_ : p - y_; | |
} | |
// Point addition, P + Q | |
// inData: Px, Py, Pz, Qx, Qy, Qz | |
// outData: Rx, Ry, Rz | |
function _add(uint[3] memory P, uint[3] memory Q) internal constant returns (uint[3] memory R) { | |
if(P[2] == 0) | |
return Q; | |
if(Q[2] == 0) | |
return P; | |
uint p = pp; | |
uint[4] memory zs; // Pz^2, Pz^3, Qz^2, Qz^3 | |
zs[0] = mulmod(P[2], P[2], p); | |
zs[1] = mulmod(P[2], zs[0], p); | |
zs[2] = mulmod(Q[2], Q[2], p); | |
zs[3] = mulmod(Q[2], zs[2], p); | |
uint[4] memory us = [ | |
mulmod(P[0], zs[2], p), | |
mulmod(P[1], zs[3], p), | |
mulmod(Q[0], zs[0], p), | |
mulmod(Q[1], zs[1], p) | |
]; // Pu, Ps, Qu, Qs | |
if (us[0] == us[2]) { | |
if (us[1] != us[3]) | |
return; | |
else { | |
return _double(P); | |
} | |
} | |
uint h = addmod(us[2], p - us[0], p); | |
uint r = addmod(us[3], p - us[1], p); | |
uint h2 = mulmod(h, h, p); | |
uint h3 = mulmod(h2, h, p); | |
uint Rx = addmod(mulmod(r, r, p), p - h3, p); | |
Rx = addmod(Rx, p - mulmod(2, mulmod(us[0], h2, p), p), p); | |
R[0] = Rx; | |
R[1] = mulmod(r, addmod(mulmod(us[0], h2, p), p - Rx, p), p); | |
R[1] = addmod(R[1], p - mulmod(us[1], h3, p), p); | |
R[2] = mulmod(h, mulmod(P[2], Q[2], p), p); | |
} | |
// Point addition, P + Q. P Jacobian, Q affine. | |
// inData: Px, Py, Pz, Qx, Qy | |
// outData: Rx, Ry, Rz | |
function _addMixed(uint[3] memory P, uint[2] memory Q) internal constant returns (uint[3] memory R) { | |
if(P[2] == 0) | |
return [Q[0], Q[1], 1]; | |
if(Q[1] == 0) | |
return P; | |
uint p = pp; | |
uint[2] memory zs; // Pz^2, Pz^3, Qz^2, Qz^3 | |
zs[0] = mulmod(P[2], P[2], p); | |
zs[1] = mulmod(P[2], zs[0], p); | |
uint[4] memory us = [ | |
P[0], | |
P[1], | |
mulmod(Q[0], zs[0], p), | |
mulmod(Q[1], zs[1], p) | |
]; // Pu, Ps, Qu, Qs | |
if (us[0] == us[2]) { | |
if (us[1] != us[3]) { | |
P[0] = 0; | |
P[1] = 0; | |
P[2] = 0; | |
return; | |
} | |
else { | |
_double(P); | |
return; | |
} | |
} | |
uint h = addmod(us[2], p - us[0], p); | |
uint r = addmod(us[3], p - us[1], p); | |
uint h2 = mulmod(h, h, p); | |
uint h3 = mulmod(h2, h, p); | |
uint Rx = addmod(mulmod(r, r, p), p - h3, p); | |
Rx = addmod(Rx, p - mulmod(2, mulmod(us[0], h2, p), p), p); | |
R[0] = Rx; | |
R[1] = mulmod(r, addmod(mulmod(us[0], h2, p), p - Rx, p), p); | |
R[1] = addmod(R[1], p - mulmod(us[1], h3, p), p); | |
R[2] = mulmod(h, P[2], p); | |
} | |
// Same as addMixed but params are different and mutates P. | |
function _addMixedM(uint[3] memory P, uint[2] memory Q) internal constant { | |
if(P[1] == 0) { | |
P[0] = Q[0]; | |
P[1] = Q[1]; | |
P[2] = 1; | |
return; | |
} | |
if(Q[1] == 0) | |
return; | |
uint p = pp; | |
uint[2] memory zs; // Pz^2, Pz^3, Qz^2, Qz^3 | |
zs[0] = mulmod(P[2], P[2], p); | |
zs[1] = mulmod(P[2], zs[0], p); | |
uint[4] memory us = [ | |
P[0], | |
P[1], | |
mulmod(Q[0], zs[0], p), | |
mulmod(Q[1], zs[1], p) | |
]; // Pu, Ps, Qu, Qs | |
if (us[0] == us[2]) { | |
if (us[1] != us[3]) { | |
P[0] = 0; | |
P[1] = 0; | |
P[2] = 0; | |
return; | |
} | |
else { | |
_doubleM(P); | |
return; | |
} | |
} | |
uint h = addmod(us[2], p - us[0], p); | |
uint r = addmod(us[3], p - us[1], p); | |
uint h2 = mulmod(h, h, p); | |
uint h3 = mulmod(h2, h, p); | |
uint Rx = addmod(mulmod(r, r, p), p - h3, p); | |
Rx = addmod(Rx, p - mulmod(2, mulmod(us[0], h2, p), p), p); | |
P[0] = Rx; | |
P[1] = mulmod(r, addmod(mulmod(us[0], h2, p), p - Rx, p), p); | |
P[1] = addmod(P[1], p - mulmod(us[1], h3, p), p); | |
P[2] = mulmod(h, P[2], p); | |
} | |
// Point doubling, 2*P | |
// Params: Px, Py, Pz | |
// Not concerned about the 1 extra mulmod. | |
function _double(uint[3] memory P) internal constant returns (uint[3] memory Q) { | |
uint p = pp; | |
if (P[2] == 0) | |
return; | |
uint Px = P[0]; | |
uint Py = P[1]; | |
uint Py2 = mulmod(Py, Py, p); | |
uint s = mulmod(4, mulmod(Px, Py2, p), p); | |
uint m = mulmod(3, mulmod(Px, Px, p), p); | |
var Qx = addmod(mulmod(m, m, p), p - addmod(s, s, p), p); | |
Q[0] = Qx; | |
Q[1] = addmod(mulmod(m, addmod(s, p - Qx, p), p), p - mulmod(8, mulmod(Py2, Py2, p), p), p); | |
Q[2] = mulmod(2, mulmod(Py, P[2], p), p); | |
} | |
// Same as double but mutates P and is internal only. | |
function _doubleM(uint[3] memory P) internal constant { | |
uint p = pp; | |
if (P[2] == 0) | |
return; | |
uint Px = P[0]; | |
uint Py = P[1]; | |
uint Py2 = mulmod(Py, Py, p); | |
uint s = mulmod(4, mulmod(Px, Py2, p), p); | |
uint m = mulmod(3, mulmod(Px, Px, p), p); | |
var PxTemp = addmod(mulmod(m, m, p), p - addmod(s, s, p), p); | |
P[0] = PxTemp; | |
P[1] = addmod(mulmod(m, addmod(s, p - PxTemp, p), p), p - mulmod(8, mulmod(Py2, Py2, p), p), p); | |
P[2] = mulmod(2, mulmod(Py, P[2], p), p); | |
} | |
// Multiplication dP. P affine, wNAF: w=5 | |
// Params: d, Px, Py | |
// Output: Jacobian Q | |
function _mul(uint d, uint[2] memory P) internal constant returns (uint[3] memory Q) { | |
uint p = pp; | |
if (d == 0) // TODO | |
return; | |
uint dwPtr; // points to array of NAF coefficients. | |
uint i; | |
// wNAF | |
assembly | |
{ | |
let dm := 0 | |
dwPtr := mload(0x40) | |
mstore(0x40, add(dwPtr, 512)) // Should lower this. | |
loop: | |
jumpi(loop_end, iszero(d)) | |
jumpi(even, iszero(and(d, 1))) | |
dm := mod(d, 32) | |
mstore8(add(dwPtr, i), dm) // Don"t store as signed - convert when reading. | |
d := add(sub(d, dm), mul(gt(dm, 16), 32)) | |
even: | |
d := div(d, 2) | |
i := add(i, 1) | |
jump(loop) | |
loop_end: | |
} | |
dwPtr = dwPtr; | |
// Pre calculation | |
uint[3][8] memory PREC; // P, 3P, 5P, 7P, 9P, 11P, 13P, 15P | |
PREC[0] = [P[0], P[1], 1]; | |
var X = _double(PREC[0]); | |
PREC[1] = _addMixed(X, P); | |
PREC[2] = _add(X, PREC[1]); | |
PREC[3] = _add(X, PREC[2]); | |
PREC[4] = _add(X, PREC[3]); | |
PREC[5] = _add(X, PREC[4]); | |
PREC[6] = _add(X, PREC[5]); | |
PREC[7] = _add(X, PREC[6]); | |
uint[16] memory INV; | |
INV[0] = PREC[1][2]; // a1 | |
INV[1] = mulmod(PREC[2][2], INV[0], p); // a2 | |
INV[2] = mulmod(PREC[3][2], INV[1], p); // a3 | |
INV[3] = mulmod(PREC[4][2], INV[2], p); // a4 | |
INV[4] = mulmod(PREC[5][2], INV[3], p); // a5 | |
INV[5] = mulmod(PREC[6][2], INV[4], p); // a6 | |
INV[6] = mulmod(PREC[7][2], INV[5], p); // a7 | |
INV[7] = ECCMath.invmod(INV[6], p); // a7inv | |
INV[8] = INV[7]; // aNinv (a7inv) | |
INV[15] = mulmod(INV[5], INV[8], p); // z7inv | |
for(uint k = 6; k >= 2; k--) { // z6inv to z2inv | |
INV[8] = mulmod(PREC[k + 1][2], INV[8], p); | |
INV[8 + k] = mulmod(INV[k - 2], INV[8], p); | |
} | |
INV[9] = mulmod(PREC[2][2], INV[8], p); // z1Inv | |
for(k = 0; k < 7; k++) { | |
ECCMath.toZ1(PREC[k + 1], INV[k + 9], mulmod(INV[k + 9], INV[k + 9], p), p); | |
} | |
// Mult loop | |
while(i > 0) { | |
uint dj; | |
uint pIdx; | |
i--; | |
assembly { | |
dj := byte(0, mload(add(dwPtr, i))) | |
} | |
_doubleM(Q); | |
if (dj > 16) { | |
pIdx = (31 - dj) / 2; // These are the "negative ones", so invert y. | |
_addMixedM(Q, [PREC[pIdx][0], p - PREC[pIdx][1]]); | |
} | |
else if (dj > 0) { | |
pIdx = (dj - 1) / 2; | |
_addMixedM(Q, [PREC[pIdx][0], PREC[pIdx][1]]); | |
} | |
} | |
} | |
} | |
contract owned { | |
address public owner; | |
/* Initialise contract creator as owner */ | |
function owned() { | |
owner = msg.sender; | |
} | |
/* Function to dictate that only the designated owner can call a function */ | |
modifier onlyOwner { | |
if(owner != msg.sender) throw; | |
_; | |
} | |
/* Transfer ownership of this contract to someone else */ | |
function transferOwnership(address newOwner) onlyOwner() { | |
owner = newOwner; | |
} | |
} | |
/* | |
* @title AnonymousVoting | |
* Open Vote Network | |
* A self-talling protocol that supports voter privacy. | |
* | |
* Author: Patrick McCorry | |
*/ | |
contract AnonymousVoting is owned { | |
// Modulus for public keys | |
uint constant pp = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; | |
// Base point (generator) G | |
uint constant Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; | |
uint constant Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8; | |
// Modulus for private keys (sub-group) | |
uint constant nn = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; | |
uint[2] G; | |
//Every address has an index | |
//This makes looping in the program easier. | |
address[] public addresses; | |
mapping (address => uint) public addressid; // Address to Counter | |
mapping (uint => Voter) public voters; | |
mapping (address => bool) public eligible; // White list of addresses allowed to vote | |
mapping (address => bool) public registered; // Address registered? | |
mapping (address => bool) public votecast; // Address voted? | |
mapping (address => bool) public commitment; // Have we received their commitment? | |
mapping (address => uint) public refunds; // Have we received their commitment? | |
struct Voter { | |
address addr; | |
uint[2] registeredkey; | |
uint[2] reconstructedkey; | |
bytes32 commitment; | |
uint[2] vote; | |
} | |
// Work around function to fetch details about a voter | |
function getVoter() returns (uint[2] _registeredkey, uint[2] _reconstructedkey, bytes32 _commitment){ | |
uint index = addressid[msg.sender]; | |
_registeredkey = voters[index].registeredkey; | |
_reconstructedkey = voters[index].reconstructedkey; | |
_commitment = voters[index].commitment; | |
} | |
// List of timers that each phase MUST end by an explicit time in UNIX timestamp. | |
// Ethereum works in SECONDS. Not milliseconds. | |
uint public finishSignupPhase; // Election Authority to transition to next phase. | |
uint public endSignupPhase; // Election Authority does not transition to next phase by this time. | |
uint public endCommitmentPhase; // Voters have not sent their commitments in by this time. | |
uint public endVotingPhase; // Voters have not submitted their vote by this stage. | |
uint public endRefundPhase; // Voters must claim their refund by this stage. | |
uint public totalregistered; //Total number of participants that have submited a voting key | |
uint public totaleligible; | |
uint public totalcommitted; | |
uint public totalvoted; | |
uint public totalrefunded; | |
uint public totaltorefund; | |
string public question; | |
uint[2] public finaltally; // Final tally | |
bool public commitmentphase; // OPTIONAL phase. | |
uint public depositrequired; | |
uint public gap; // Minimum amount of time between time stamps. | |
address public charity; | |
// TODO: Why cant election authority receive the spoils? | |
uint public lostdeposit; // This money is collected from non active voters... | |
enum State { SETUP, SIGNUP, COMMITMENT, VOTE, FINISHED } | |
State public state; | |
modifier inState(State s) { | |
if(state != s) { | |
throw; | |
} | |
_; | |
} | |
// 2 round anonymous voting protocol | |
// TODO: Right now due to gas limits there is an upper limit | |
// on the number of participants that we can have voting... | |
// I need to split the functions up... so if they cannot | |
// finish their entire workload in 1 transaction, then | |
// it does the maximum. This way we can chain transactions | |
// to complete the job... | |
function AnonymousVoting(uint _gap, address _charity) { | |
G[0] = Gx; | |
G[1] = Gy; | |
state = State.SETUP; | |
question = "No question set"; | |
gap = _gap; // Minimum gap period between stages | |
charity = _charity; | |
} | |
// Owner of contract sets a whitelist of addresses that are eligible to vote. | |
function setEligible(address[] addr) onlyOwner { | |
// We can only handle up 50 people at the moment. | |
if(totaleligible > 50) { | |
throw; | |
} | |
// Sign up the addresses | |
for(uint i=0; i<addr.length; i++) { | |
if(!eligible[addr[i]]) { | |
eligible[addr[i]] = true; | |
addresses.push(addr[i]); | |
totaleligible += 1; | |
} | |
} | |
} | |
// Owner of contract declares that eligible addresses begin round 1 of the protocol | |
// Time is the number of 'blocks' we must wait until we can move onto round 2. | |
function beginSignUp(string _question, bool enableCommitmentPhase, uint _finishSignupPhase, uint _endSignupPhase, uint _endCommitmentPhase, uint _endVotingPhase, uint _endRefundPhase, uint _depositrequired) inState(State.SETUP) onlyOwner payable returns (bool){ | |
// We have lots of timers. let's explain each one | |
// _finishSignUpPhase - Voters should be signed up before this timer | |
// Voter is refunded if any of the timers expire: | |
// _endSignUpPhase - Election Authority never finished sign up phase | |
// _endCommitmentPhase - One or more voters did not send their commitments in time | |
// _endVotingPhase - One or more voters did not send their votes in time | |
// _endRefundPhase - Provide time for voters to get their money back. | |
// Why is there no endTally? Because anyone can call it! | |
// Represented in UNIX time... | |
// TODO: Set to block timestamp... | |
// TODO: Enforce gap to be at least 1 hour.. may break unit testing | |
// Make sure 3 people are at least eligible to vote.. | |
// Deposit can be zero or more WEI | |
if(_finishSignupPhase > 0 + gap && addresses.length >= 3 && _depositrequired >= 0) { | |
// Ensure each time phase finishes in the future... | |
// Ensure there is a gap of 'x time' between each phase. | |
if(_endSignupPhase-gap < _finishSignupPhase) { | |
return false; | |
} | |
// We need to check Commitment timestamps if phase is enabled. | |
if(enableCommitmentPhase) { | |
// Make sure there is a gap between 'end of registration' and 'end of commitment' phases. | |
if(_endCommitmentPhase-gap < _endSignupPhase) { | |
return false; | |
} | |
// Make sure there is a gap between 'end of commitment' and 'end of vote' phases. | |
if(_endVotingPhase-gap < _endCommitmentPhase) { | |
return false; | |
} | |
} else { | |
// We have no commitment phase. | |
// Make sure there is a gap between 'end of registration' and 'end of vote' phases. | |
if(_endVotingPhase-gap < _endSignupPhase) { | |
return false; | |
} | |
} | |
// Provide time for people to get a refund once the voting phase has ended. | |
if(_endRefundPhase-gap < _endVotingPhase) { | |
return false; | |
} | |
// Require Election Authority to deposit ether. | |
if(msg.value != _depositrequired) { | |
return false; | |
} | |
// Store the election authority's deposit | |
// Note: This deposit is only lost if the | |
// election authority does not begin the election | |
// or call the tally function before the timers expire. | |
refunds[msg.sender] = msg.value; | |
// All time stamps are reasonable. | |
// We can now begin the signup phase. | |
state = State.SIGNUP; | |
// All timestamps should be in UNIX.. | |
finishSignupPhase = _finishSignupPhase; | |
endSignupPhase = _endSignupPhase; | |
endCommitmentPhase = _endCommitmentPhase; | |
endVotingPhase = _endVotingPhase; | |
endRefundPhase = _endRefundPhase; | |
question = _question; | |
commitmentphase = enableCommitmentPhase; | |
depositrequired = _depositrequired; // Deposit required from all voters | |
return true; | |
} | |
return false; | |
} | |
// This function determines if one of the deadlines have been missed | |
// If a deadline has been missed - then we finish the election, | |
// and allocate refunds to the correct people depending on the situation. | |
function deadlinePassed() returns (bool){ | |
uint refund = 0; | |
// Has the Election Authority missed the signup deadline? | |
// Election Authority will forfeit his deposit. | |
if(state == State.SIGNUP && block.timestamp > endSignupPhase) { | |
// Nothing to do. All voters are refunded. | |
state = State.FINISHED; | |
totaltorefund = totalregistered; | |
// Election Authority forfeits his deposit... | |
// If 3 or more voters had signed up... | |
if(addresses.length >= 3) { | |
// Election Authority forfeits deposit | |
refund = refunds[owner]; | |
refunds[owner] = 0; | |
lostdeposit = lostdeposit + refund; | |
} | |
return true; | |
} | |
// Has a voter failed to send their commitment? | |
// Election Authority DOES NOT forgeit his deposit. | |
if(state == State.COMMITMENT && block.timestamp > endCommitmentPhase) { | |
// Check which voters have not sent their commitment | |
for(uint i=0; i<totalregistered; i++) { | |
// Voters forfeit their deposit if failed to send a commitment | |
if(!commitment[voters[i].addr]) { | |
refund = refunds[voters[i].addr]; | |
refunds[voters[i].addr] = 0; | |
lostdeposit = lostdeposit + refund; | |
} else { | |
// We will need to refund this person. | |
totaltorefund = totaltorefund + 1; | |
} | |
} | |
state = State.FINISHED; | |
return true; | |
} | |
// Has a voter failed to send in their vote? | |
// Eletion Authority does NOT forfeit his deposit. | |
if(state == State.VOTE && block.timestamp > endVotingPhase) { | |
// Check which voters have not cast their vote | |
for(i=0; i<totalregistered; i++) { | |
// Voter forfeits deposit if they have not voted. | |
if(!votecast[voters[i].addr]) { | |
refund = refunds[voters[i].addr]; | |
refunds[voters[i].addr] = 0; | |
lostdeposit = lostdeposit + refund; | |
} else { | |
// Lets make sure refund has not already been issued... | |
if(refunds[voters[i].addr] > 0) { | |
// We will need to refund this person. | |
totaltorefund = totaltorefund + 1; | |
} | |
} | |
} | |
state = State.FINISHED; | |
return true; | |
} | |
// Has the deadline passed for voters to claim their refund? | |
// Only owner can call. Owner must be refunded (or forfeited). | |
// Refund period is over or everyone has already been refunded. | |
if(state == State.FINISHED && msg.sender == owner && refunds[owner] == 0 && (block.timestamp > endRefundPhase || totaltorefund == totalrefunded)) { | |
// Collect all unclaimed refunds. We will send it to charity. | |
for(i=0; i<totalregistered; i++) { | |
refund = refunds[voters[i].addr]; | |
refunds[voters[i].addr] = 0; | |
lostdeposit = lostdeposit + refund; | |
} | |
uint[2] memory empty; | |
for(i=0; i<addresses.length; i++) { | |
address addr = addresses[i]; | |
eligible[addr] = false; // No longer eligible | |
registered[addr] = false; // Remove voting registration | |
voters[i] = Voter({addr: 0, registeredkey: empty, reconstructedkey: empty, vote: empty, commitment: 0}); | |
addressid[addr] = 0; // Remove index | |
votecast[addr] = false; // Remove that vote was cast | |
commitment[addr] = false; | |
} | |
// Reset timers. | |
finishSignupPhase = 0; | |
endSignupPhase = 0; | |
endCommitmentPhase = 0; | |
endVotingPhase = 0; | |
endRefundPhase = 0; | |
delete addresses; | |
// Keep track of voter activity | |
totalregistered = 0; | |
totaleligible = 0; | |
totalcommitted = 0; | |
totalvoted = 0; | |
// General values that need reset | |
question = "No question set"; | |
finaltally[0] = 0; | |
finaltally[1] = 0; | |
commitmentphase = false; | |
depositrequired = 0; | |
totalrefunded = 0; | |
totaltorefund = 0; | |
state = State.SETUP; | |
return true; | |
} | |
// No deadlines have passed... | |
return false; | |
} | |
// Called by participants to register their voting public key | |
// Participant mut be eligible, and can only register the first key sent key. | |
function register(uint[2] xG, uint[3] vG, uint r) inState(State.SIGNUP) payable returns (bool) { | |
// HARD DEADLINE | |
if(block.timestamp > finishSignupPhase) { | |
throw; // throw returns the voter's ether, but exhausts their gas. | |
} | |
// Make sure the ether being deposited matches what we expect. | |
if(msg.value != depositrequired) { | |
return false; | |
} | |
// Only white-listed addresses can vote | |
if(eligible[msg.sender]) { | |
if(verifyZKP(xG,r,vG) && !registered[msg.sender]) { | |
// Store deposit | |
refunds[msg.sender] = msg.value; | |
// Update voter's registration | |
uint[2] memory empty; | |
addressid[msg.sender] = totalregistered; | |
voters[totalregistered] = Voter({addr: msg.sender, registeredkey: xG, reconstructedkey: empty, vote: empty, commitment: 0}); | |
registered[msg.sender] = true; | |
totalregistered += 1; | |
return true; | |
} | |
} | |
return false; | |
} | |
// Timer has expired - we want to start computing the reconstructed keys | |
function finishRegistrationPhase() inState(State.SIGNUP) onlyOwner returns(bool) { | |
// Make sure at least 3 people have signed up... | |
if(totalregistered < 3) { | |
return; | |
} | |
// We can only compute the public keys once participants | |
// have been given an opportunity to register their | |
// voting public key. | |
if(block.timestamp < finishSignupPhase) { | |
return; | |
} | |
// Election Authority has a deadline to begin election | |
if(block.timestamp > endSignupPhase) { | |
return; | |
} | |
uint[2] memory temp; | |
uint[3] memory yG; | |
uint[3] memory beforei; | |
uint[3] memory afteri; | |
// Step 1 is to compute the index 1 reconstructed key | |
afteri[0] = voters[1].registeredkey[0]; | |
afteri[1] = voters[1].registeredkey[1]; | |
afteri[2] = 1; | |
for(uint i=2; i<totalregistered; i++) { | |
Secp256k1._addMixedM(afteri, voters[i].registeredkey); | |
} | |
ECCMath.toZ1(afteri,pp); | |
voters[0].reconstructedkey[0] = afteri[0]; | |
voters[0].reconstructedkey[1] = pp - afteri[1]; | |
// Step 2 is to add to beforei, and subtract from afteri. | |
for(i=1; i<totalregistered; i++) { | |
if(i==1) { | |
beforei[0] = voters[0].registeredkey[0]; | |
beforei[1] = voters[0].registeredkey[1]; | |
beforei[2] = 1; | |
} else { | |
Secp256k1._addMixedM(beforei, voters[i-1].registeredkey); | |
} | |
// If we have reached the end... just store beforei | |
// Otherwise, we need to compute a key. | |
// Counting from 0 to n-1... | |
if(i==(totalregistered-1)) { | |
ECCMath.toZ1(beforei,pp); | |
voters[i].reconstructedkey[0] = beforei[0]; | |
voters[i].reconstructedkey[1] = beforei[1]; | |
} else { | |
// Subtract 'i' from afteri | |
temp[0] = voters[i].registeredkey[0]; | |
temp[1] = pp - voters[i].registeredkey[1]; | |
// Grab negation of afteri (did not seem to work with Jacob co-ordinates) | |
Secp256k1._addMixedM(afteri,temp); | |
ECCMath.toZ1(afteri,pp); | |
temp[0] = afteri[0]; | |
temp[1] = pp - afteri[1]; | |
// Now we do beforei - afteri... | |
yG = Secp256k1._addMixed(beforei, temp); | |
ECCMath.toZ1(yG,pp); | |
voters[i].reconstructedkey[0] = yG[0]; | |
voters[i].reconstructedkey[1] = yG[1]; | |
} | |
} | |
// We have computed each voter's special voting key. | |
// Now we either enter the commitment phase (option) or voting phase. | |
if(commitmentphase) { | |
state = State.COMMITMENT; | |
} else { | |
state = State.VOTE; | |
} | |
} | |
/* | |
* OPTIONAL STAGE: All voters submit the hash of their vote. | |
* Why? The final voter that submits their vote gets to see the tally result | |
* before anyone else. This provides the voter with an additional advantage | |
* compared to all other voters. To get around this issue; we can force all | |
* voters to commit to their vote in advance.... and votes are only revealed | |
* once all voters have committed. This way the final voter has no additional | |
* advantage as they cannot change their vote depending on the tally. | |
* However... we cannot enforce the pre-image to be a hash, and someone could | |
* a commitment that is not a vote. This will break the election, but you | |
* will be able to determine who did it (and possibly punish them!). | |
*/ | |
function submitCommitment(bytes32 h) inState(State.COMMITMENT) { | |
//All voters have a deadline to send their commitment | |
if(block.timestamp > endCommitmentPhase) { | |
return; | |
} | |
if(!commitment[msg.sender]) { | |
commitment[msg.sender] = true; | |
uint index = addressid[msg.sender]; | |
voters[index].commitment = h; | |
totalcommitted = totalcommitted + 1; | |
// Once we have recorded all commitments... let voters vote! | |
if(totalcommitted == totalregistered) { | |
state = State.VOTE; | |
} | |
} | |
} | |
// Given the 1 out of 2 ZKP - record the users vote! | |
function submitVote(uint[4] params, uint[2] y, uint[2] a1, uint[2] b1, uint[2] a2, uint[2] b2) inState(State.VOTE) returns (bool) { | |
// HARD DEADLINE | |
if(block.timestamp > endVotingPhase) { | |
return; | |
} | |
uint c = addressid[msg.sender]; | |
// Make sure the sender can vote, and hasn't already voted. | |
if(registered[msg.sender] && !votecast[msg.sender]) { | |
// OPTIONAL Phase: Voters need to commit to their vote in advance. | |
// Time to verify if this vote matches the voter's previous commitment. | |
if(commitmentphase) { | |
// Voter has previously committed to the entire zero knowledge proof... | |
bytes32 h = sha3(msg.sender, params, voters[c].registeredkey, voters[c].reconstructedkey, y, a1, b1, a2, b2); | |
// No point verifying the ZKP if it doesn't match the voter's commitment. | |
if(voters[c].commitment != h) { | |
return false; | |
} | |
} | |
// Verify the ZKP for the vote being cast | |
if(verify1outof2ZKP(params, y, a1, b1, a2, b2)) { | |
voters[c].vote[0] = y[0]; | |
voters[c].vote[1] = y[1]; | |
votecast[msg.sender] = true; | |
totalvoted += 1; | |
// Refund the sender their ether.. | |
// Voter has finished their part of the protocol... | |
uint refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
// We can still fail... Safety first. | |
// If failed... voter can call withdrawRefund() | |
// to collect their money once the election has finished. | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return true; | |
} | |
} | |
// Either vote has already been cast, or ZKP verification failed. | |
return false; | |
} | |
// Assuming all votes have been submitted. We can leak the tally. | |
// We assume Election Authority performs this function. It could be anyone. | |
// Election Authority gets deposit upon tallying. | |
// TODO: Anyone can do this function. Perhaps remove refund code - and force Election Authority | |
// to explicit withdraw it? Election cannot reset until he is refunded - so that should be OK | |
function computeTally() inState(State.VOTE) onlyOwner { | |
uint[3] memory temp; | |
uint[2] memory vote; | |
uint refund; | |
// Sum all votes | |
for(uint i=0; i<totalregistered; i++) { | |
// Confirm all votes have been cast... | |
if(!votecast[voters[i].addr]) { | |
throw; | |
} | |
vote = voters[i].vote; | |
if(i==0) { | |
temp[0] = vote[0]; | |
temp[1] = vote[1]; | |
temp[2] = 1; | |
} else { | |
Secp256k1._addMixedM(temp, vote); | |
} | |
} | |
// All votes have been accounted for... | |
// Get tally, and change state to 'Finished' | |
state = State.FINISHED; | |
// All voters should already be refunded! | |
for(i = 0; i<totalregistered; i++) { | |
// Sanity check.. make sure refunds have been issued.. | |
if(refunds[voters[i].addr] > 0) { | |
totaltorefund = totaltorefund + 1; | |
} | |
} | |
// Each vote is represented by a G. | |
// If there are no votes... then it is 0G = (0,0)... | |
if(temp[0] == 0) { | |
finaltally[0] = 0; | |
finaltally[1] = totalregistered; | |
// Election Authority is responsible for calling this.... | |
// He should not fail his own refund... | |
// Make sure tally is computed before refunding... | |
// TODO: Check if this is necessary | |
refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return; | |
} else { | |
// There must be a vote. So lets | |
// start adding 'G' until we | |
// find the result. | |
ECCMath.toZ1(temp,pp); | |
uint[3] memory tempG; | |
tempG[0] = G[0]; | |
tempG[1] = G[1]; | |
tempG[2] = 1; | |
// Start adding 'G' and looking for a match | |
for(i=1; i<=totalregistered; i++) { | |
if(temp[0] == tempG[0]) { | |
finaltally[0] = i; | |
finaltally[1] = totalregistered; | |
// Election Authority is responsible for calling this.... | |
// He should not fail his own refund... | |
// Make sure tally is computed before refunding... | |
// TODO: Check if this is necessary | |
// If it fails - he can use withdrawRefund() | |
// Election cannot be reset until he is refunded. | |
refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return; | |
} | |
// If something bad happens and we cannot find the Tally | |
// Then this 'addition' will be run 1 extra time due to how | |
// we have structured the for loop. | |
// TODO: Does it need fixed? | |
Secp256k1._addMixedM(tempG, G); | |
ECCMath.toZ1(tempG,pp); | |
} | |
// Something bad happened. We should never get here.... | |
// This represents an error message... best telling people | |
// As we cannot recover from it anyway. | |
// TODO: Handle this better.... | |
finaltally[0] = 0; | |
finaltally[1] = 0; | |
// Election Authority is responsible for calling this.... | |
// He should not fail his own refund... | |
// TODO: Check if this is necessary | |
refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} | |
return; | |
} | |
} | |
// There are two reasons why we might be in a finished state | |
// 1. The tally has been computed | |
// 2. A deadline has been missed. | |
// In the former; everyone gets a refund. In the latter; only active participants get a refund | |
// We can assume if the deadline has been missed - then refunds has ALREADY been updated to | |
// take that into account. (a transaction is required to indicate a deadline has been missed | |
// and in that transaction - we can penalise the non-active participants. lazy sods!) | |
function withdrawRefund() inState(State.FINISHED){ | |
uint refund = refunds[msg.sender]; | |
refunds[msg.sender] = 0; | |
if (!msg.sender.send(refund)) { | |
refunds[msg.sender] = refund; | |
} else { | |
// Tell everyone we have issued the refund. | |
// Owner is not included in refund counter. | |
// This is OK - we cannot reset election until | |
// the owner has been refunded... | |
// Counter only concerns voters! | |
if(msg.sender != owner) { | |
totalrefunded = totalrefunded + 1; | |
} | |
} | |
} | |
// Send the lost deposits to a charity. Anyone can call it. | |
// Lost Deposit increments for each failed election. It is only | |
// reset upon sending to the charity! | |
function sendToCharity() { | |
// Only send this money to the owner | |
uint profit = lostdeposit; | |
lostdeposit = 0; | |
// Try to send money | |
if(!charity.send(profit)) { | |
// We failed to send the money. Record it again. | |
lostdeposit = profit; | |
} | |
} | |
// Parameters xG, r where r = v - xc, and vG. | |
// Verify that vG = rG + xcG! | |
function verifyZKP(uint[2] xG, uint r, uint[3] vG) returns (bool){ | |
uint[2] memory G; | |
G[0] = Gx; | |
G[1] = Gy; | |
// Check both keys are on the curve. | |
if(!Secp256k1.isPubKey(xG) || !Secp256k1.isPubKey(vG)) { | |
return false; //Must be on the curve! | |
} | |
// Get c = H(g, g^{x}, g^{v}); | |
bytes32 b_c = sha256(msg.sender, Gx, Gy, xG, vG); | |
uint c = uint(b_c); | |
// Get g^{r}, and g^{xc} | |
uint[3] memory rG = Secp256k1._mul(r, G); | |
uint[3] memory xcG = Secp256k1._mul(c, xG); | |
// Add both points together | |
uint[3] memory rGxcG = Secp256k1._add(rG,xcG); | |
// Convert to Affine Co-ordinates | |
ECCMath.toZ1(rGxcG, pp); | |
// Verify. Do they match? | |
if(rGxcG[0] == vG[0] && rGxcG[1] == vG[1]) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
// We verify that the ZKP is of 0 or 1. | |
function verify1outof2ZKP(uint[4] params, uint[2] y, uint[2] a1, uint[2] b1, uint[2] a2, uint[2] b2) returns (bool) { | |
uint[2] memory temp1; | |
uint[3] memory temp2; | |
uint[3] memory temp3; | |
// Voter Index | |
uint i = addressid[msg.sender]; | |
// We already have them stored... | |
// TODO: Decide if this should be in SubmitVote or here... | |
uint[2] memory yG = voters[i].reconstructedkey; | |
uint[2] memory xG = voters[i].registeredkey; | |
// Make sure we are only dealing with valid public keys! | |
if(!Secp256k1.isPubKey(xG) || !Secp256k1.isPubKey(yG) || !Secp256k1.isPubKey(y) || !Secp256k1.isPubKey(a1) || | |
!Secp256k1.isPubKey(b1) || !Secp256k1.isPubKey(a2) || !Secp256k1.isPubKey(b2)) { | |
return false; | |
} | |
// Does c =? d1 + d2 (mod n) | |
if(uint(sha256(msg.sender, xG, y, a1, b1, a2, b2)) != addmod(params[0],params[1],nn)) { | |
return false; | |
} | |
// a1 =? g^{r1} * x^{d1} | |
temp2 = Secp256k1._mul(params[2], G); | |
temp3 = Secp256k1._add(temp2, Secp256k1._mul(params[0], xG)); | |
ECCMath.toZ1(temp3, pp); | |
if(a1[0] != temp3[0] || a1[1] != temp3[1]) { | |
return false; | |
} | |
//b1 =? h^{r1} * y^{d1} (temp = affine 'y') | |
temp2 = Secp256k1._mul(params[2],yG); | |
temp3 = Secp256k1._add(temp2, Secp256k1._mul(params[0], y)); | |
ECCMath.toZ1(temp3, pp); | |
if(b1[0] != temp3[0] || b1[1] != temp3[1]) { | |
return false; | |
} | |
//a2 =? g^{r2} * x^{d2} | |
temp2 = Secp256k1._mul(params[3],G); | |
temp3 = Secp256k1._add(temp2, Secp256k1._mul(params[1], xG)); | |
ECCMath.toZ1(temp3, pp); | |
if(a2[0] != temp3[0] || a2[1] != temp3[1]) { | |
return false; | |
} | |
// Negate the 'y' co-ordinate of g | |
temp1[0] = G[0]; | |
temp1[1] = pp - G[1]; | |
// get 'y' | |
temp3[0] = y[0]; | |
temp3[1] = y[1]; | |
temp3[2] = 1; | |
// y-g | |
temp2 = Secp256k1._addMixed(temp3,temp1); | |
// Return to affine co-ordinates | |
ECCMath.toZ1(temp2, pp); | |
temp1[0] = temp2[0]; | |
temp1[1] = temp2[1]; | |
// (y-g)^{d2} | |
temp2 = Secp256k1._mul(params[1],temp1); | |
// Now... it is h^{r2} + temp2.. | |
temp3 = Secp256k1._add(Secp256k1._mul(params[3],yG),temp2); | |
// Convert to Affine Co-ordinates | |
ECCMath.toZ1(temp3, pp); | |
// Should all match up. | |
if(b2[0] != temp3[0] || b2[1] != temp3[1]) { | |
return false; | |
} | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract MyPlate{ | |
uint public price = 1 wei; | |
struct Vehicle{ | |
string plate_id; | |
address owner_address; | |
string chungloai; | |
string characteristics; | |
string ngaycap; | |
uint256 balances; | |
} | |
struct Citizen{ | |
address citizenID; | |
string fName; | |
string lName; | |
string birthDay; | |
string queQuan; | |
string[] plate_ids; | |
} | |
mapping (address => Citizen) citizens; | |
address[] public citizenList; | |
function addCitizen(address _address, string _f, string _l, string _birthDay, string _queQuan) public{ | |
Citizen storage citizen = citizens[_address]; | |
citizen.citizenID=_address; | |
citizen.fName=_f; | |
citizen.lName=_l; | |
citizen.birthDay=_birthDay; | |
citizen.queQuan=_queQuan; | |
citizenList.push(_address) -1; | |
} | |
function getCitizen(address _address) public view returns(address, string){ | |
return (citizens[_address].citizenID, citizens[_address].plate_ids[0]); | |
} | |
mapping (string =>Vehicle) vehicles; | |
string[] public vehiclesList; | |
function getPrice() public view returns(uint256){ | |
return price; | |
} | |
function setPrice(uint256 _new_price) public{ | |
if (price>0){ | |
price = _new_price; | |
} | |
else{ | |
revert(); | |
} | |
} | |
function addVehicle(string _plate_id, address _owner_address, string _type, string _charac, string _ngaycap, uint256 _balances) public{ | |
Vehicle storage vehicle = vehicles[_plate_id]; | |
citizens[_owner_address].plate_ids.push(_plate_id) -1; | |
vehicle.plate_id = _plate_id; | |
vehicle.owner_address=_owner_address; | |
vehicle.chungloai=_type; | |
vehicle.characteristics=_charac; | |
vehicle.ngaycap=_ngaycap; | |
vehicle.balances=_balances; | |
vehiclesList.push(_plate_id) -1; | |
} | |
function getVehicle(string _plate_id) view public returns (address, string, string, string, uint256){ | |
return (vehicles[_plate_id].owner_address, vehicles[_plate_id].chungloai, vehicles[_plate_id].characteristics, vehicles[_plate_id].ngaycap, vehicles[_plate_id].balances); | |
} | |
function addCoin(string _plate_id, uint256 amount) payable public{ | |
if (msg.value !=amount*price){ | |
revert(); | |
} | |
vehicles[_plate_id].balances+= amount; | |
} | |
function verifyVehicle(string _plate_id) public returns (bool result){ | |
if (vehicles[_plate_id].balances<price) return false; | |
else { | |
vehicles[_plate_id].balances=vehicles[_plate_id].balances - price; | |
return true; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.11; | |
contract Exchanges { | |
mapping (address => uint256) public balances; | |
event LogDeposit(address sender, uint amount); | |
event LogWithdrawal(address receiver, uint amount); | |
event LogTransfer(address sender, address to, uint amount); | |
function deposit() payable returns(bool success) { | |
balances[msg.sender] +=msg.value; | |
LogDeposit(msg.sender, msg.value); | |
return true; | |
} | |
function withdraw(uint value) returns(bool success) { | |
if(balances[msg.sender] < value) throw; | |
balances[msg.sender] -= value; | |
msg.sender.transfer(value); | |
LogWithdrawal(msg.sender, value); | |
return true; | |
} | |
function transfer(address to, uint value) returns(bool success) { | |
if(balances[msg.sender] < value) throw; | |
balances[msg.sender] -= value; | |
to.transfer(value); | |
LogTransfer(msg.sender, to, value); | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract Test { | |
uint[] sotunhien; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.17; | |
contract Payment { | |
address transferFrom; | |
address transferTo; | |
constructor() public { | |
transferFrom = msg.sender; | |
} | |
event TransferFund(address _transferTo, address _transferFrom, uint amount); | |
function transferFund( address _transferTo ) public payable returns (bool){ | |
transferTo = _transferTo; | |
transferTo.transfer(msg.value); | |
emit TransferFund(transferTo, transferFrom, msg.value); | |
return true; | |
} | |
function getBalanceOfCurrentAccount() public payable returns (uint) { | |
return transferFrom.balance; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.18; | |
contract Citizen { | |
uint public a = 1; | |
co | |
function setA(uint _a) public returns (uint) { | |
a = _a; | |
return a; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract VehiclesManagement{ | |
struct Vehicle{ | |
string plate_id; | |
address owner; | |
string name; | |
string typeOfVehicle; | |
string color; | |
string yearOfPro; | |
string yearOfRegis; | |
string charactic; | |
string manufac; | |
string serial; | |
string status; //active, deactive, stolen. | |
} | |
mapping (string => Vehicle) vehicles; | |
string[] public vehiclesList; | |
function addVehicle(address _owner, string _plate_id, string _name, string _type, string _color, string _yearOfPro, string _yearOfRegis, string _charac, string _manufac, string _serial, string _status) public{ | |
Vehicle storage vehicle = vehicles[_plate_id]; | |
vehicle.owner = _owner; | |
vehicle.plate_id = _plate_id; | |
vehicle.name = _name; | |
vehicle.typeOfVehicle = _type; | |
vehicle.color = _color; | |
vehicle.yearOfPro = _yearOfPro; | |
vehicle.yearOfRegis = _yearOfRegis; | |
vehicle.charactic = _charac; | |
vehicle.manufac = _manufac; | |
vehicle.serial = _serial; | |
vehicle.status = _status; | |
vehiclesList.push(_plate_id) -1; | |
} | |
function getFixedInfo(string _plate_id) view public returns (string, string, string, string, string) { | |
return(vehicles[_plate_id].name, vehicles[_plate_id].typeOfVehicle, vehicles[_plate_id].yearOfPro, vehicles[_plate_id].manufac, vehicles[_plate_id].serial); | |
} | |
function getDynamicInfo(string _plate_id) view public returns (address, string, string, string, string){ | |
//return (vehicles[_plate_id].owner, vehicles[_plate_id].name, vehicles[_plate_id]. typeOfVehicle, vehicles[_plate_id].color, vehicles[_plate_id].yearOfPro, vehicles[_plate_id].yearOfRegis, vehicles[_plate_id].charactic, vehicles[_plate_id].manufac, vehicles[_plate_id].serial, vehicles[_plate_id]. status ); | |
return (vehicles[_plate_id]. owner, vehicles[_plate_id].color, vehicles[_plate_id].charactic, vehicles[_plate_id].yearOfRegis, vehicles[_plate_id].status); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract VehiclesManagement{ | |
struct Vehicle{ | |
string plate_id; | |
address owner; | |
string name; | |
string typeOfVehicle; | |
string color; | |
string yearOfPro; | |
string yearOfRegis; | |
string charactic; | |
string manufac; | |
string serial; | |
string status; //active, deactive, stolen. | |
} | |
mapping (string => Vehicle) vehicles; | |
string[] public vehiclesList; | |
function addVehicle(string _plate_id, string name, string _type, string _color, string _yearOfPro, string _yearOfRegis, string _charac, string _manufac, string _serial, string _status) public{ | |
Vehicle storage vehicle = vehicles[_plate_id]; | |
vehicle.plate_id = _plate_id; | |
vehicle.typeOfVehicle = _type; | |
vehicle.color = _color; | |
vehicle.yearOfPro = _yearOfPro; | |
vehicle.yearOfRegis = _yearOfRegis; | |
vehicle.charactic = _charac; | |
vehicle.manufac = _manufac; | |
vehicle.serial = _serial; | |
vehiclesList.push(_plate_id) -1; | |
} | |
function getVehicle(string _plate_id) view public returns (string){ | |
return (vehicles[_plate_id].name); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract VehiclesManagement{ | |
struct Vehicle{ | |
string plate_id; | |
address owner; | |
string name; | |
string typeOfVehicle; | |
string color; | |
string yearOfPro; | |
string yearOfRegis; | |
string charactic; | |
string manufac; | |
string serial; | |
string status; //active, deactive, stolen. | |
} | |
mapping (string => Vehicle) vehicles; | |
string[] public vehiclesList; | |
function addVehicle(address _owner, string _plate_id, string _name, string _type, string _color, string _yearOfPro, string _yearOfRegis, string _charac, string _manufac, string _serial, string _status) public{ | |
Vehicle storage vehicle = vehicles[_plate_id]; | |
vehicle.owner = _owner; | |
vehicle.plate_id = _plate_id; | |
vehicle.name = _name; | |
vehicle.typeOfVehicle = _type; | |
vehicle.color = _color; | |
vehicle.yearOfPro = _yearOfPro; | |
vehicle.yearOfRegis = _yearOfRegis; | |
vehicle.charactic = _charac; | |
vehicle.manufac = _manufac; | |
vehicle.serial = _serial; | |
vehicle.status = _status; | |
vehiclesList.push(_plate_id) -1; | |
} | |
function getFixedInfo(string _plate_id) view public returns (string, string, string, string, string) { | |
return(vehicles[_plate_id].name, vehicles[_plate_id].typeOfVehicle, vehicles[_plate_id].yearOfPro, vehicles[_plate_id].manufac, vehicles[_plate_id].serial); | |
} | |
function getDynamicInfo(string _plate_id) view public returns (address, string, string, string, string){ | |
//return (vehicles[_plate_id].owner, vehicles[_plate_id].name, vehicles[_plate_id]. typeOfVehicle, vehicles[_plate_id].color, vehicles[_plate_id].yearOfPro, vehicles[_plate_id].yearOfRegis, vehicles[_plate_id].charactic, vehicles[_plate_id].manufac, vehicles[_plate_id].serial, vehicles[_plate_id]. status ); | |
return (vehicles[_plate_id]. owner, vehicles[_plate_id].color, vehicles[_plate_id].charactic, vehicles[_plate_id].yearOfRegis, vehicles[_plate_id].status); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment