Files
hash.kt/src/commonMain/kotlin/com/infendro/hash/sha1/SHA1.kt
2026-01-15 22:06:28 +01:00

77 lines
2.2 KiB
Kotlin

package com.infendro.hash.sha1
import com.infendro.bytes.bytearray.copyInto
import com.infendro.bytes.intarray.copyInto
import com.infendro.bytes.ulong.copyInto
import com.infendro.hash.HashFunction
import com.infendro.hash.util.ceilPow2
object SHA1 : HashFunction {
override val bytes: Int
get() = 20
override val block: Int
get() = 64
private val initial = uintArrayOf(
0x67452301U, 0xefcdaB89U,
0x98badcfeU, 0x10325476U,
0xc3d2e1f0U,
).asIntArray()
private val k = uintArrayOf(
0x5a827999U, 0x6ed9eba1U,
0x8f1bbcdcU, 0xca62c1d6U,
).asIntArray()
override fun hashInto(value: ByteArray, destination: ByteArray) {
val input = pad(value)
val h = initial.copyOf()
val w = IntArray(80)
val v = IntArray(5)
for (i in input.indices step block) {
process(h, input, i, w, v)
}
h.copyInto(destination)
}
private fun pad(value: ByteArray): ByteArray {
val length = value.size.toULong() * 8UL
val size = ceilPow2(value.size + 9, block)
val result = ByteArray(size)
value.copyInto(result)
result[value.size] = 0x80U.toByte()
length.copyInto(result, result.size - 8)
return result
}
private fun process(h: IntArray, value: ByteArray, offset: Int, w: IntArray, v: IntArray) {
value.copyInto(w, startIndex = offset, endIndex = offset + block)
for (i in 16..<80) {
w[i] = (w[i - 3] xor w[i - 8] xor w[i - 14] xor w[i - 16]).rotateLeft(1)
}
h.copyInto(v)
repeat(80) { i ->
val f = when (i) {
in 0..<20 -> (v[1] and v[2]) or (v[1].inv() and v[3])
in 20..<40 -> v[1] xor v[2] xor v[3]
in 40..<60 -> (v[1] and v[2]) or (v[1] and v[3]) or (v[2] and v[3])
else -> v[1] xor v[2] xor v[3]
}
val temp = v[0].rotateLeft(5) + f + v[4] + k[i / 20] + w[i]
v[4] = v[3]
v[3] = v[2]
v[2] = v[1].rotateLeft(30)
v[1] = v[0]
v[0] = temp
}
for (i in 0..<5) {
h[i] += v[i]
}
}
}