Skip to content

Instantly share code, notes, and snippets.

@yaronvel
Created January 25, 2017 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yaronvel/1478182d0bd49dad58bcd0c4edf5ae3e to your computer and use it in GitHub Desktop.
Save yaronvel/1478182d0bd49dad58bcd0c4edf5ae3e to your computer and use it in GitHub Desktop.
contract SHA3_512_Wrapper {
function sponge(uint[9] M) constant returns(uint[16]);
}
contract Ethash {
SHA3_512_Wrapper sha3_512;
function Ethash() {
sha3_512 = SHA3_512_Wrapper(0xe78a0f7e598cc8b0bb87894b0f60dd2a88d6a8ab);
}
uint merkleRoot = 0xcddd312dd2c15f394a49b417cd01bd2cabe7b863cbe3b65bfa22e4012da15bb4;
function setMerkleRoot(uint root) {
merkleRoot = root;
}
/*
function sha3_512(bytes32 header, bytes8 nonceLe ) constant returns (uint[16]) {
return [uint(0),1,2,3,4,5,6,7,8,9,10,11,12,13,14,16];
}*/
function fnv( uint v1, uint v2 ) constant returns(uint) {
return ((v1*0x01000193) ^ v2) & 0xFFFFFFFF;
}
function computeCacheRoot( uint index,
uint[] dataSetLookup,
uint[] witness,
uint witnessIndex ) constant returns(uint) {
uint leaf = uint( sha3(dataSetLookup[4*witnessIndex],
dataSetLookup[4*witnessIndex + 1],
dataSetLookup[4*witnessIndex + 2],
dataSetLookup[4*witnessIndex + 3]) );
uint[4] memory offsets = [ uint(2**0), 2**64, 2**128, 2**192];
uint left;
uint right;
// witness[] stores 5 uint per cache element, each uint is 4 nodes
for( uint depth = 0 ; depth < 20 ; depth++ ) {
leaf = leaf & 0xFFFFFFFFFFFFFFFF;
// use offsets array to avoid expensive exp
uint node = (witness[5*witnessIndex + depth/4] / offsets[depth%4])&0xFFFFFFFFFFFFFFFF;
if( index & 0x1 > 0 ) {
left = leaf;
right = node;
}
else {
left = node;
right = leaf;
}
leaf = uint(sha3(left,right));
index = index / 2;
}
return leaf;
}
function toBE( uint x ) constant returns(uint) {
uint y = 0;
for( uint i = 0 ; i < 32 ; i++ ) {
y = y * 256;
y += (x & 0xFF);
x = x / 256;
}
return y;
}
function computeSha3( uint[16] s, uint[8] cmix ) constant returns(uint) {
uint s0 = s[0] + s[1] * (2**32) + s[2] * (2**64) + s[3] * (2**96) +
(s[4] + s[5] * (2**32) + s[6] * (2**64) + s[7] * (2**96))*(2**128);
uint s1 = s[8] + s[9] * (2**32) + s[10] * (2**64) + s[11] * (2**96) +
(s[12] + s[13] * (2**32) + s[14] * (2**64) + s[15] * (2**96))*(2**128);
uint c = cmix[0] + cmix[1] * (2**32) + cmix[2] * (2**64) + cmix[3] * (2**96) +
(cmix[4] + cmix[5] * (2**32) + cmix[6] * (2**64) + cmix[7] * (2**96))*(2**128);
/* god knows why need to convert to big endian */
return uint( sha3(toBE(s0),toBE(s1),toBE(c)) );
}
event Log( string msg, uint i, uint p );
function hashimoto( bytes32 header,
bytes8 nonceLe,
uint fullSize,
uint[] dataSetLookup,
uint[] witnessForLookup ) constant returns(uint) {
uint[16] memory s;
uint[32] memory mix;
uint[8] memory cmix;
uint[9] memory M;
uint i;
uint j;
uint headerAsInt = uint(header);
M[0] = uint(headerAsInt) & 0xFFFFFFFFFFFFFFFF;
headerAsInt = headerAsInt / 2**64;
M[1] = uint(headerAsInt) & 0xFFFFFFFFFFFFFFFF;
headerAsInt = headerAsInt / 2**64;
M[2] = uint(headerAsInt) & 0xFFFFFFFFFFFFFFFF;
headerAsInt = headerAsInt / 2**64;
M[3] = uint(headerAsInt) & 0xFFFFFFFFFFFFFFFF;
M[4] = uint(nonceLe);
s = sha3_512.sponge(M);
for( i = 0 ; i < 16 ; i++ ) {
mix[i] = s[i];
mix[i+16] = s[i];
}
for( i = 0 ; i < 64 ; i++ ) {
uint p = (fnv( i ^ s[0], mix[i % 32]) % (fullSize / 2)) * 2;
/*
if( computeCacheRoot(p,dataSetLookup,witnessForLookup,i) != merkleRoot ) {
// PoW failed
Log("computeCacheRoot failed", i, p);
return 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
}*/
for( j = 0 ; j < 8 ; j++ ) {
mix[j] = fnv(mix[j], dataSetLookup[4*i] & 0xFFFFFFFF );
mix[j+8] = fnv(mix[j+8], dataSetLookup[4*i + 1] & 0xFFFFFFFF );
mix[j+16] = fnv(mix[j+16], dataSetLookup[4*i + 2] & 0xFFFFFFFF );
mix[j+24] = fnv(mix[j+24], dataSetLookup[4*i + 3] & 0xFFFFFFFF );
dataSetLookup[4*i ] = dataSetLookup[4*i ]/(2**32);
dataSetLookup[4*i + 1] = dataSetLookup[4*i + 1]/(2**32);
dataSetLookup[4*i + 2] = dataSetLookup[4*i + 2]/(2**32);
dataSetLookup[4*i + 3] = dataSetLookup[4*i + 3]/(2**32);
}
}
for( i = 0 ; i < 32 ; i += 4) {
cmix[i/4] = (fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3]));
}
Log("Ok",0,0);
return computeSha3(s,cmix);
}
function h(uint32 x, uint32 y) constant returns(uint) {
uint32[2] memory z;
z[0] = x;
z[1] = y;
return uint(sha3(z));
}
}
pragma solidity ^0.4.1;
contract SHA3_512 {
function SHA3_512() {}
event Result(uint result);
function keccak_f(uint[25] A) constant returns(uint[25]) {
uint[5] memory C;
uint D_0; uint D_1; uint D_2; uint D_3; uint D_4;
uint[25] memory B;
uint[24] memory RC= [
uint(0x0000000000000001),
0x0000000000008082,
0x800000000000808A,
0x8000000080008000,
0x000000000000808B,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008A,
0x0000000000000088,
0x0000000080008009,
0x000000008000000A,
0x000000008000808B,
0x800000000000008B,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800A,
0x800000008000000A,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008 ];
for( uint i = 0 ; i < 24 ; i++ ) {
/* Theta step */
C[0]=A[0]^A[1]^A[2]^A[3]^A[4];
C[1]=A[5]^A[6]^A[7]^A[8]^A[9];
C[2]=A[10]^A[11]^A[12]^A[13]^A[14];
C[3]=A[15]^A[16]^A[17]^A[18]^A[19];
C[4]=A[20]^A[21]^A[22]^A[23]^A[24];
D_0=C[4] ^ ((C[1] * 2)&0xffffffffffffffff | (C[1] / (2 ** 63)));
D_1=C[0] ^ ((C[2] * 2)&0xffffffffffffffff | (C[2] / (2 ** 63)));
D_2=C[1] ^ ((C[3] * 2)&0xffffffffffffffff | (C[3] / (2 ** 63)));
D_3=C[2] ^ ((C[4] * 2)&0xffffffffffffffff | (C[4] / (2 ** 63)));
D_4=C[3] ^ ((C[0] * 2)&0xffffffffffffffff | (C[0] / (2 ** 63)));
A[0]=A[0] ^ D_0;
A[1]=A[1] ^ D_0;
A[2]=A[2] ^ D_0;
A[3]=A[3] ^ D_0;
A[4]=A[4] ^ D_0;
A[5]=A[5] ^ D_1;
A[6]=A[6] ^ D_1;
A[7]=A[7] ^ D_1;
A[8]=A[8] ^ D_1;
A[9]=A[9] ^ D_1;
A[10]=A[10] ^ D_2;
A[11]=A[11] ^ D_2;
A[12]=A[12] ^ D_2;
A[13]=A[13] ^ D_2;
A[14]=A[14] ^ D_2;
A[15]=A[15] ^ D_3;
A[16]=A[16] ^ D_3;
A[17]=A[17] ^ D_3;
A[18]=A[18] ^ D_3;
A[19]=A[19] ^ D_3;
A[20]=A[20] ^ D_4;
A[21]=A[21] ^ D_4;
A[22]=A[22] ^ D_4;
A[23]=A[23] ^ D_4;
A[24]=A[24] ^ D_4;
/*Rho and pi steps*/
B[0]=A[0];
B[8]=((A[1] * (2 ** 36))&0xffffffffffffffff | (A[1] / (2 ** 28)));
B[11]=((A[2] * (2 ** 3))&0xffffffffffffffff | (A[2] / (2 ** 61)));
B[19]=((A[3] * (2 ** 41))&0xffffffffffffffff | (A[3] / (2 ** 23)));
B[22]=((A[4] * (2 ** 18))&0xffffffffffffffff | (A[4] / (2 ** 46)));
B[2]=((A[5] * (2 ** 1))&0xffffffffffffffff | (A[5] / (2 ** 63)));
B[5]=((A[6] * (2 ** 44))&0xffffffffffffffff | (A[6] / (2 ** 20)));
B[13]=((A[7] * (2 ** 10))&0xffffffffffffffff | (A[7] / (2 ** 54)));
B[16]=((A[8] * (2 ** 45))&0xffffffffffffffff | (A[8] / (2 ** 19)));
B[24]=((A[9] * (2 ** 2))&0xffffffffffffffff | (A[9] / (2 ** 62)));
B[4]=((A[10] * (2 ** 62))&0xffffffffffffffff | (A[10] / (2 ** 2)));
B[7]=((A[11] * (2 ** 6))&0xffffffffffffffff | (A[11] / (2 ** 58)));
B[10]=((A[12] * (2 ** 43))&0xffffffffffffffff | (A[12] / (2 ** 21)));
B[18]=((A[13] * (2 ** 15))&0xffffffffffffffff | (A[13] / (2 ** 49)));
B[21]=((A[14] * (2 ** 61))&0xffffffffffffffff | (A[14] / (2 ** 3)));
B[1]=((A[15] * (2 ** 28))&0xffffffffffffffff | (A[15] / (2 ** 36)));
B[9]=((A[16] * (2 ** 55))&0xffffffffffffffff | (A[16] / (2 ** 9)));
B[12]=((A[17] * (2 ** 25))&0xffffffffffffffff | (A[17] / (2 ** 39)));
B[15]=((A[18] * (2 ** 21))&0xffffffffffffffff | (A[18] / (2 ** 43)));
B[23]=((A[19] * (2 ** 56))&0xffffffffffffffff | (A[19] / (2 ** 8)));
B[3]=((A[20] * (2 ** 27))&0xffffffffffffffff | (A[20] / (2 ** 37)));
B[6]=((A[21] * (2 ** 20))&0xffffffffffffffff | (A[21] / (2 ** 44)));
B[14]=((A[22] * (2 ** 39))&0xffffffffffffffff | (A[22] / (2 ** 25)));
B[17]=((A[23] * (2 ** 8))&0xffffffffffffffff | (A[23] / (2 ** 56)));
B[20]=((A[24] * (2 ** 14))&0xffffffffffffffff | (A[24] / (2 ** 50)));
/*Xi state*/
A[0]=B[0]^((~B[5]) & B[10]);
A[1]=B[1]^((~B[6]) & B[11]);
A[2]=B[2]^((~B[7]) & B[12]);
A[3]=B[3]^((~B[8]) & B[13]);
A[4]=B[4]^((~B[9]) & B[14]);
A[5]=B[5]^((~B[10]) & B[15]);
A[6]=B[6]^((~B[11]) & B[16]);
A[7]=B[7]^((~B[12]) & B[17]);
A[8]=B[8]^((~B[13]) & B[18]);
A[9]=B[9]^((~B[14]) & B[19]);
A[10]=B[10]^((~B[15]) & B[20]);
A[11]=B[11]^((~B[16]) & B[21]);
A[12]=B[12]^((~B[17]) & B[22]);
A[13]=B[13]^((~B[18]) & B[23]);
A[14]=B[14]^((~B[19]) & B[24]);
A[15]=B[15]^((~B[20]) & B[0]);
A[16]=B[16]^((~B[21]) & B[1]);
A[17]=B[17]^((~B[22]) & B[2]);
A[18]=B[18]^((~B[23]) & B[3]);
A[19]=B[19]^((~B[24]) & B[4]);
A[20]=B[20]^((~B[0]) & B[5]);
A[21]=B[21]^((~B[1]) & B[6]);
A[22]=B[22]^((~B[2]) & B[7]);
A[23]=B[23]^((~B[3]) & B[8]);
A[24]=B[24]^((~B[4]) & B[9]);
/*Last step*/
A[0]=A[0]^RC[i];
}
return A;
}
function sponge(uint[9] M) constant returns(uint[16]) {
if( (M.length * 8) != 72 ) throw;
M[5] = 0x01;
M[8] = 0x8000000000000000;
uint r = 72;
uint w = 8;
uint size = M.length * 8;
uint[25] memory S;
uint i; uint y; uint x;
/*Absorbing Phase*/
for( i = 0 ; i < size/r ; i++ ) {
for( y = 0 ; y < 5 ; y++ ) {
for( x = 0 ; x < 5 ; x++ ) {
if( (x+5*y) < (r/w) ) {
S[5*x+y] = S[5*x+y] ^ M[i*9 + x + 5*y];
}
}
}
S = keccak_f(S);
}
/*Squeezing phase*/
uint[16] memory result;
uint b = 0;
while( b < 16 ) {
for( y = 0 ; y < 5 ; y++ ) {
for( x = 0 ; x < 5 ; x++ ) {
if( (x+5*y)<(r/w) && (b<16) ) {
result[b] = S[5*x+y] & 0xFFFFFFFF;
result[b+1] = S[5*x+y] / 0x100000000;
b+=2;
}
}
}
}
Result(result[0]);
Result(result[1]);
Result(result[2]);
Result(result[3]);
Result(result[4]);
Result(result[5]);
Result(result[6]);
Result(result[7]);
Result(result[8]);
Result(result[9]);
Result(result[10]);
Result(result[11]);
Result(result[12]);
Result(result[13]);
Result(result[14]);
Result(result[15]);
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment