package com.infendro.hash.sha1 import com.infendro.bytearray.toUByteArray import com.infendro.bytearray.toUIntArray import com.infendro.hash.HashFunction object SHA1 : HashFunction() { override val bytes: Int get() = 20 override val block: Int get() = 64 override fun hash( value: UByteArray, ): UByteArray { var h0 = 0x67452301U var h1 = 0xefcdaB89U var h2 = 0x98badcfeU var h3 = 0x10325476U var h4 = 0xc3d2e1f0U val ml = value.size.toULong() * 8UL val paddedValue = buildList { addAll(value) add(0x80U) while (size % 64 != 56) { add(0x00U) } addAll(ml.toUByteArray()) } val chunks = paddedValue .chunked(64) { it.toUByteArray() } for (chunk in chunks) { val w = buildList { addAll(chunk.toUIntArray()) for (i in 16..<80) { val word = (get(i - 3) xor get(i - 8) xor get(i - 14) xor get(i - 16)).rotateLeft(1) add(word) } } var a = h0 var b = h1 var c = h2 var d = h3 var e = h4 for (i in 0..<80) { val f = when (i) { in 0..<20 -> (b and c) or (b.inv() and d) in 20..<40 -> b xor c xor d in 40..<60 -> (b and c) or (b and d) or (c and d) else -> b xor c xor d } val k = when (i) { in 0..<20 -> 0x5a827999U in 20..<40 -> 0x6ed9eba1U in 40..<60 -> 0x8f1bbcdcU else -> 0xca62c1d6U } val temp = a.rotateLeft(5) + f + e + k + w[i] e = d d = c c = b.rotateLeft(30) b = a a = temp } h0 += a h1 += b h2 += c h3 += d h4 += e } return ubyteArrayOf( *h0.toUByteArray(), *h1.toUByteArray(), *h2.toUByteArray(), *h3.toUByteArray(), *h4.toUByteArray(), ) } }