Created
July 1, 2014 14:39
-
-
Save zhanzhenzhen/26ae03f40c41b111a15f to your computer and use it in GitHub Desktop.
SHA-256 in Wishlist
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
### | |
Copyright(c) Zhenzhen Zhan | |
MIT License | |
Why use SHA-256? Is it OK to use CRC32? My answer is: | |
The reason is for security. There's a potential issue if we use a weak checksum algorithm. | |
If the tests include "get info from the web", then attackers may have the ability to affect the units' | |
true/false results that lead to the same checksum. | |
These are "user"-caused collisions, which need to be avoided logically. In contrast, | |
it's not necessary when it comes to "developer"-caused deliberate collisions, | |
like "386389655257694535" in my "js-bundler" repo. | |
If another library deliberately uses this name, we can simply discard this library and | |
choose another. | |
I strictly followed the steps on: | |
http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf | |
In doing math power and division, I use `round` to avoid possible fractions in old engine. | |
### | |
npmWishlist.sha256 = (str) -> | |
if str.length > Math.round(Math.pow(2, 31) - 1) | |
throw new Error() | |
wordToString = (n) -> (((n >>> (i * 4)) % 16).toString(16) for i in [7..0]).join("") | |
add = -> | |
r = 0 | |
for arg in arguments | |
r = (r + arg) % 0x100000000 | |
r | |
ROTR = (x, n) -> x >>> n | x << (32 - n) | |
SHR = (x, n) -> x >>> n | |
Ch = (x, y, z) -> (x & y) ^ (~x & z) | |
Maj = (x, y, z) -> (x & y) ^ (x & z) ^ (y & z) | |
SIGMA0 = (x) -> ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22) | |
SIGMA1 = (x) -> ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25) | |
sigma0 = (x) -> ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3) | |
sigma1 = (x) -> ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10) | |
K = [ | |
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 | |
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 | |
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da | |
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 | |
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 | |
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 | |
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 | |
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 | |
] | |
# preprocessing ========================================[ | |
H = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19] | |
bytes = str.split("").map((m) -> m.charCodeAt(0)) | |
l = str.length * 8 | |
k = 448 - l - 1 | |
while k < 0 | |
k += 512 | |
paddedLength = l + 1 + k + 64 | |
bytes.push(0x80) | |
for i in [0...Math.round((k - 7) / 8)] | |
bytes.push(0) | |
# This only supports max length of 2^32. But it's enough for testing. -----[ | |
bytes.push(0) | |
bytes.push(0) | |
bytes.push(0) | |
bytes.push(0) | |
bytes.push(l >>> 24) | |
bytes.push((l >>> 16) % 256) | |
bytes.push((l >>> 8) % 256) | |
bytes.push(l % 256) | |
# ]-------------------- | |
N = Math.round(paddedLength / 512) | |
M = new Array(N) | |
for i in [0...N] | |
M[i] = new Array(16) | |
for j in [0...16] | |
offset = i * 64 + j * 4 | |
M[i][j] = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | | |
(bytes[offset + 2] << 8) | bytes[offset + 3] | |
# ]==================== hash computation ====================[ | |
W = new Array(64) | |
for i in [0...N] | |
for t in [0...64] | |
W[t] = | |
if t < 16 | |
M[i][t] | |
else | |
add(sigma1(W[t - 2]), W[t - 7], sigma0(W[t - 15]), W[t - 16]) | |
a = H[0] | |
b = H[1] | |
c = H[2] | |
d = H[3] | |
e = H[4] | |
f = H[5] | |
g = H[6] | |
h = H[7] | |
for t in [0...64] | |
T1 = add(h, SIGMA1(e), Ch(e, f, g), K[t], W[t]) | |
T2 = add(SIGMA0(a), Maj(a, b, c)) | |
h = g | |
g = f | |
f = e | |
e = add(d, T1) | |
d = c | |
c = b | |
b = a | |
a = add(T1, T2) | |
H[0] = add(a, H[0]) | |
H[1] = add(b, H[1]) | |
H[2] = add(c, H[2]) | |
H[3] = add(d, H[3]) | |
H[4] = add(e, H[4]) | |
H[5] = add(f, H[5]) | |
H[6] = add(g, H[6]) | |
H[7] = add(h, H[7]) | |
# ]======================================== | |
H.map((m) -> wordToString(m)).join("") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment