diff --git a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt new file mode 100644 index 0000000..9a2295a --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt @@ -0,0 +1,121 @@ +package com.infendro.hash.blake2 + +import com.infendro.bytearray.ByteOrder +import com.infendro.bytearray.toUByteArray +import com.infendro.bytearray.toULongArray +import com.infendro.hash.HashFunction + +class Blake2b( + override val bytes: Int, +) : HashFunction() { + init { + if (bytes !in 1..64) throw IllegalArgumentException() + } + + override val block: Int + get() = 128 + + private val initial = ulongArrayOf( + 0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL, + 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, + 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, + 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, + ) + + private val sigma = arrayOf( + intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), + intArrayOf(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), + intArrayOf(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), + intArrayOf(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), + intArrayOf(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), + intArrayOf(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), + intArrayOf(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), + intArrayOf(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), + intArrayOf(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), + intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), + ) + + override fun hash(value: UByteArray): UByteArray { + val h = initial.copyOf() + h[0] = h[0] xor (0x01010000UL or bytes.toULong()) + var t = 0UL + val l = value.size.toULong() + + // padding + val paddedValue = buildList { + addAll(value) + if (isEmpty()) add(0x00U) + while (size % 128 != 0) { + add(0x00U) + } + }.toUByteArray() + + // compress + val blocks = paddedValue + .chunked(128) { it.toUByteArray() } + for ((i, block) in blocks.withIndex()) { + t += minOf(l - t, 128UL) + + val m = block.toULongArray() + compress(h, m, t, i == blocks.lastIndex) + } + + return h.toUByteArray(ByteOrder.LITTLE_ENDIAN).sliceArray(0..