66 lines
1.6 KiB
CoffeeScript
66 lines
1.6 KiB
CoffeeScript
# Array sum helper function.
|
|
sum = (array) ->
|
|
array.reduce (x, y) -> x + y
|
|
|
|
md5 = do ->
|
|
# Per-round shift amounts.
|
|
s = [738695, 669989, 770404, 703814]
|
|
s = (s[i >> 4] >> i % 4 * 5 & 31 for i in [0..63])
|
|
|
|
# Constants cache generated by sine.
|
|
K = (Math.floor 2**32 * Math.abs Math.sin i for i in [1..64])
|
|
|
|
# Bitwise left rotate helper function.
|
|
lrot = (x, y) ->
|
|
x << y | x >>> 32 - y;
|
|
|
|
(input) ->
|
|
# Initialize values.
|
|
d0 = 0x10325476;
|
|
a0 = 0x67452301;
|
|
b0 = ~d0
|
|
c0 = ~a0;
|
|
|
|
# Convert the message to 32-bit words, little-endian.
|
|
M =
|
|
for i in [0...input.length] by 4
|
|
sum (input.charCodeAt(i + j) << j*8 for j in [0..3])
|
|
|
|
# Pre-processing: append a 1 bit, then message length % 2^64.
|
|
len = input.length * 8
|
|
M[len >> 5] |= 128 << len % 32
|
|
M[(len + 64 >>> 9 << 4) + 14] = len
|
|
|
|
# Process the message in chunks of 16 32-bit words.
|
|
for x in [0...M.length] by 16
|
|
[A, B, C, D] = [a0, b0, c0, d0]
|
|
|
|
# Main loop.
|
|
for i in [0..63]
|
|
if i < 16
|
|
F = B & C | ~B & D
|
|
g = i
|
|
else if i < 32
|
|
F = B & D | C & ~D
|
|
g = i * 5 + 1
|
|
else if i < 48
|
|
F = B ^ C ^ D
|
|
g = i * 3 + 5
|
|
else
|
|
F = C ^ (B | ~D)
|
|
g = i * 7
|
|
|
|
[A, B, C, D] =
|
|
[D, B + lrot(A + F + K[i] + (M[x + g % 16] ? 0), s[i]), B, C]
|
|
|
|
a0 += A
|
|
b0 += B
|
|
c0 += C
|
|
d0 += D
|
|
|
|
# Convert the four words back to a string.
|
|
return (
|
|
for x in [a0, b0, c0, d0]
|
|
(String.fromCharCode x >>> 8 * y & 255 for y in [0..3]).join ''
|
|
).join ''
|