Created
November 24, 2016 15:50
-
-
Save D-Nice/43d60515263f9854bd92e952dfc0dea5 to your computer and use it in GitHub Desktop.
This file contains 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.0; | |
contract SHA1 { | |
uint8[4] shift = [3, 8, 14, 16]; | |
uint constant leftAlign = 16**56; | |
uint constant prep = 16**55; //allow extra bits as requested in spec | |
uint constant h0 = 1732584193 * prep; //0x67452301 | |
uint constant h1 = 4023233417 * prep; //0xEFCDAB89 | |
uint constant h2 = 2562383102 * prep; //0x98BADCFE | |
uint constant h3 = 271733878 * prep; //0x10325476 | |
uint constant h4 = 3285377520 * prep; //0xC3D2E1F0 | |
uint[4] K = [1518500249 * prep, 1859775393 * prep, 2400959708 * prep, 3395469782 * prep]; | |
//0x5A827999 //0x6ED9EBA1 //8F1BBCDC //CA62C1D6 | |
event logHash(string, bytes); | |
function run(string _m) returns (bytes h) { | |
bytes memory raw = bytes(_m); | |
//PREPARE PRE-PROCESSING | |
uint reusedPos = raw.length + 32; //reusing due to stack depth limit | |
//BEGIN 1-BIT APPEND AT LAST CHAR | |
assembly { | |
let extraBitShift := mload(0x40) | |
extraBitShift := exp(16, 62) | |
mstore(add(raw, reusedPos), mul(0x80, extraBitShift)) | |
} | |
uint[2] memory A; | |
A[0] = h0; | |
uint[2] memory B; | |
B[0] = h1; | |
uint[2] memory C; | |
C[0] = h2; | |
uint[2] memory D; | |
D[0] = h3; | |
uint[2] memory E; | |
E[0] = h4; | |
uint rawMsgLen; | |
for(uint chunk = 0; chunk <= (raw.length - (raw.length / 64) * 8) / 56; chunk++) { | |
bytes memory tmp = new bytes(64); | |
if(chunk == (raw.length - (raw.length / 64) * 8) / 56) | |
rawMsgLen = raw.length * 8; | |
reusedPos = 32 + (64 * chunk); //didnt know | |
//BEGIN CHAR LENGTH APPEND AT ENDING OF LAST 64-BITS | |
//CHUNK MESSAGE TO 512-BITS | |
assembly { | |
let endBits := mload(0x40) | |
endBits := mload(add(raw, add(reusedPos, 32))) | |
//endBits := and(endBits, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000) | |
//no need for above | |
endBits := or(endBits, rawMsgLen) | |
mstore(add(tmp, 0), 0x20) //mem offset | |
mstore(add(tmp, 64), mload(add(raw, reusedPos))) | |
mstore(add(tmp, 96), endBits) | |
mstore(add(tmp, 32), 64) | |
} | |
//BREAK 512-BIT CHUNK INTO SIXTEEN 32-BIT WORDS | |
uint[80] memory t; | |
//~ 15k gas cost used up to here | |
for(var i = 0; i < 16; i++) { | |
assembly { | |
mstore(add(t, mul(i, 32)), and(mload(add(tmp, add(64, mul(i, 4)))), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)) | |
} | |
} | |
t = expandWords(t); | |
(A[1], B[1], C[1], D[1], E[1]) = (hashLoop(t, A[0], B[0], C[0], D[0], E[0])); | |
A[0] = ((A[0] + A[1]) * 16) / 16; //add then truncate | |
B[0] = ((B[0] + B[1]) * 16) / 16; | |
C[0] = ((C[0] + C[1]) * 16) / 16; | |
D[0] = ((D[0] + D[1]) * 16) / 16; | |
E[0] = ((E[0] + E[1]) * 16) / 16; | |
} | |
A[0] *= 16; | |
B[0] /= 16 ** 7; | |
C[0] /= 16 ** 15; | |
D[0] /= 16 ** 23; | |
E[0] /= 16 ** 31; | |
h = toBytes20ish(A[0] + B[0] + C[0] + D[0] + E[0]); | |
logHash(_m, h); | |
} | |
function expandWords(uint[80] t) private returns (uint[80]) { | |
for(var i = 16; i < t.length; i++) {//~1800 gas per round | |
uint tRes; | |
uint tNext; | |
// ROTL1(((i-3 XOR i-8) XOR i-14) XOR i-16) | |
for (var x = 1; x < 4; x++) { | |
if (x == 1) | |
tRes = t[i-shift[0]]; | |
tNext = t[i-shift[x]]; | |
tRes = tRes ^ tNext; | |
} | |
assembly { | |
mstore(add(t, mul(i, 32)), and(or(div(tRes, exp(2,31)), mul(tRes, exp(2,1))), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)) | |
} | |
} | |
return t; | |
} | |
function hashLoop(uint[80] t, uint a, uint b, uint c, uint d, uint e) | |
private returns (uint A, uint B, uint C, uint D, uint E) { | |
A = a; | |
B = b; | |
C = c; | |
D = d; | |
E = e; | |
uint f; | |
uint m; | |
for (var i = 0; i < t.length; i++) { //~1200 gas cost per round | |
if (i <= 19) | |
f = f_1(t[i], B, C, D); | |
else if (i <= 39 || i >= 60) | |
f = f_2(t[i], B, C, D); | |
else if (i <= 59) | |
f = f_3(t[i], B, C, D); | |
m = ROTL(A, 5) + f + E + K[i/20] + t[i]/16; | |
m = m * 16; //truncate result | |
E = D; | |
D = C; | |
C = ((ROTL(B, 30) * 16) / leftAlign) * prep; | |
B = A; | |
A = (m / leftAlign) * prep; | |
} | |
} | |
function f_1(uint t, uint B, uint C, uint D) | |
private | |
returns (uint f) { | |
f = B & C; | |
f = f | ~B & D; | |
} | |
function f_2(uint t, uint B, uint C, uint D) | |
private | |
returns (uint f) { | |
f = B ^ C; | |
f = f ^ D; | |
} | |
function f_3(uint t, uint B, uint C, uint D) | |
private | |
returns (uint f) { | |
f = ((B & C) | (B & D)) | C & D; | |
} | |
function toBytes20ish(uint256 x) private constant returns (bytes b) { | |
b = new bytes(20); | |
assembly { mstore(add(b, 32), x) } | |
} | |
//not fully working, issue when doing larger uints | |
function toBytes20(uint256 x) private constant returns (bytes20 b) { | |
assembly { | |
x | |
0x01000000000000000000000000 | |
mul | |
swap1 | |
dup1 | |
mstore | |
} | |
} | |
function ROTL(uint x, uint y) private returns (uint rotated) { | |
assembly { | |
rotated := or(div(x, exp(2, sub(32, y))), mul(x, exp(2,y))) | |
} | |
} | |
} |
I am trying to add some precompiled contract to my private blockchain. But I got some problems in customizing solidity compiler. Do you have any idea?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This contract was made with optimization in mind. It mostly produces correct hashes from testing, but it's not guaranteed.
This contract https://gist.github.com/D-Nice/cafa05d2fa4dc0859f14e2ce3de5b344 has not failed one hash test, but is more expensive.