From 16390b0308b3ad1bb2f226a5f8962403455a1884 Mon Sep 17 00:00:00 2001 From: Infendro Date: Thu, 4 Dec 2025 19:05:54 +0100 Subject: [PATCH] refactor Blake and Blake2 --- .../com/infendro/hash/blake/Blake-224.kt | 42 +++++++++---------- .../com/infendro/hash/blake/Blake-256.kt | 42 +++++++++---------- .../com/infendro/hash/blake/Blake-384.kt | 42 +++++++++---------- .../com/infendro/hash/blake/Blake-512.kt | 42 +++++++++---------- .../com/infendro/hash/blake2/Blake2b.kt | 41 ++++++++---------- .../com/infendro/hash/blake2/Blake2s.kt | 40 ++++++++---------- 6 files changed, 112 insertions(+), 137 deletions(-) diff --git a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-224.kt b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-224.kt index 375e18d..d9765a3 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-224.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-224.kt @@ -43,12 +43,25 @@ object `Blake-224` : HashFunction() { ) override fun hash(value: UByteArray): UByteArray { + val l = value.size.toULong() * 8UL val h = initial.copyOf() var t = 0U - val l = value.size.toULong() * 8UL - // padding - val paddedValue = buildList { + val blocks = pad(value) + .chunked(64) { it.toUByteArray() } + for (block in blocks) { + t += minOf(l - t, 512UL).toUInt() + compress(h, block, t) + } + + return h.sliceArray(0..6).toUByteArray() + } + + private fun pad( + value: UByteArray, + ): UByteArray { + val l = value.size.toULong() * 8UL + return buildList { addAll(value) add(0x80U) while (size % 64 != 56) { @@ -56,56 +69,39 @@ object `Blake-224` : HashFunction() { } addAll(l.toUByteArray()) }.toUByteArray() - - // compress - val blocks = paddedValue - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 512UL).toUInt() - - val m = block.toUIntArray() - compress(h, m, t) - } - - return h.sliceArray(0..6).toUByteArray() } private fun compress( h: UIntArray, - m: UIntArray, + block: UByteArray, t: UInt, ) { - // initialization + val m = block.toUIntArray() val v = UIntArray(16) for (i in 0..<8) v[i] = h[i] for (i in 0..<4) v[i + 8] = c[i] for (i in 0..<2) v[i + 12] = c[i + 4] xor t for (i in 0..<2) v[i + 14] = c[i + 6] - // rounds - for (r in 0..<14) { + repeat(14) { r -> val s = sigma[r % 10] - // column g(v, 0, 4, 8, 12, m[s[0]] xor c[s[1]], m[s[1]] xor c[s[0]]) g(v, 1, 5, 9, 13, m[s[2]] xor c[s[3]], m[s[3]] xor c[s[2]]) g(v, 2, 6, 10, 14, m[s[4]] xor c[s[5]], m[s[5]] xor c[s[4]]) g(v, 3, 7, 11, 15, m[s[6]] xor c[s[7]], m[s[7]] xor c[s[6]]) - // diagonal g(v, 0, 5, 10, 15, m[s[8]] xor c[s[9]], m[s[9]] xor c[s[8]]) g(v, 1, 6, 11, 12, m[s[10]] xor c[s[11]], m[s[11]] xor c[s[10]]) g(v, 2, 7, 8, 13, m[s[12]] xor c[s[13]], m[s[13]] xor c[s[12]]) g(v, 3, 4, 9, 14, m[s[14]] xor c[s[15]], m[s[15]] xor c[s[14]]) } - // finalization for (i in 0..7) { h[i] = h[i] xor v[i] xor v[i + 8] } } - // round function private fun g( v: UIntArray, a: Int, diff --git a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-256.kt b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-256.kt index 1412a20..380d424 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-256.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-256.kt @@ -43,12 +43,25 @@ object `Blake-256` : HashFunction() { ) override fun hash(value: UByteArray): UByteArray { + val l = value.size.toULong() * 8UL val h = initial.copyOf() var t = 0U - val l = value.size.toULong() * 8UL - // padding - val paddedValue = buildList { + val blocks = pad(value) + .chunked(64) { it.toUByteArray() } + for (block in blocks) { + t += minOf(l - t, 512UL).toUInt() + compress(h, block, t) + } + + return h.toUByteArray() + } + + private fun pad( + value: UByteArray, + ): UByteArray { + val l = value.size.toULong() * 8UL + return buildList { addAll(value) add(0x80U) while (size % 64 != 55) { @@ -57,56 +70,39 @@ object `Blake-256` : HashFunction() { add(0x01U) addAll(l.toUByteArray()) }.toUByteArray() - - // compress - val blocks = paddedValue - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 512UL).toUInt() - - val m = block.toUIntArray() - compress(h, m, t) - } - - return h.toUByteArray() } private fun compress( h: UIntArray, - m: UIntArray, + block: UByteArray, t: UInt, ) { - // initialization + val m = block.toUIntArray() val v = UIntArray(16) for (i in 0..<8) v[i] = h[i] for (i in 0..<4) v[i + 8] = c[i] for (i in 0..<2) v[i + 12] = c[i + 4] xor t for (i in 0..<2) v[i + 14] = c[i + 6] - // rounds - for (r in 0..<14) { + repeat(14) { r -> val s = sigma[r % 10] - // column g(v, 0, 4, 8, 12, m[s[0]] xor c[s[1]], m[s[1]] xor c[s[0]]) g(v, 1, 5, 9, 13, m[s[2]] xor c[s[3]], m[s[3]] xor c[s[2]]) g(v, 2, 6, 10, 14, m[s[4]] xor c[s[5]], m[s[5]] xor c[s[4]]) g(v, 3, 7, 11, 15, m[s[6]] xor c[s[7]], m[s[7]] xor c[s[6]]) - // diagonal g(v, 0, 5, 10, 15, m[s[8]] xor c[s[9]], m[s[9]] xor c[s[8]]) g(v, 1, 6, 11, 12, m[s[10]] xor c[s[11]], m[s[11]] xor c[s[10]]) g(v, 2, 7, 8, 13, m[s[12]] xor c[s[13]], m[s[13]] xor c[s[12]]) g(v, 3, 4, 9, 14, m[s[14]] xor c[s[15]], m[s[15]] xor c[s[14]]) } - // finalization for (i in 0..7) { h[i] = h[i] xor v[i] xor v[i + 8] } } - // round function private fun g( v: UIntArray, a: Int, diff --git a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-384.kt b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-384.kt index 49c0442..45518e3 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-384.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-384.kt @@ -43,12 +43,25 @@ object `Blake-384` : HashFunction() { ) override fun hash(value: UByteArray): UByteArray { + val l = value.size.toULong() * 8UL val h = initial.copyOf() var t = 0UL - val l = value.size.toULong() * 8UL - // padding - val paddedValue = buildList { + val blocks = pad(value) + .chunked(128) { it.toUByteArray() } + for (block in blocks) { + t += minOf(l - t, 1024UL) + compress(h, block, t) + } + + return h.sliceArray(0..5).toUByteArray() + } + + private fun pad( + value: UByteArray, + ): UByteArray { + val l = value.size.toULong() * 8UL + return buildList { addAll(value) add(0x80U) while (size % 128 != 120) { @@ -56,56 +69,39 @@ object `Blake-384` : HashFunction() { } addAll(l.toUByteArray()) }.toUByteArray() - - // compress - val blocks = paddedValue - .chunked(128) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 1024UL) - - val m = block.toULongArray() - compress(h, m, t) - } - - return h.sliceArray(0..5).toUByteArray() } private fun compress( h: ULongArray, - m: ULongArray, + block: UByteArray, t: ULong, ) { - // initialization + val m = block.toULongArray() val v = ULongArray(16) for (i in 0..<8) v[i] = h[i] for (i in 0..<4) v[i + 8] = c[i] for (i in 0..<2) v[i + 12] = c[i + 4] xor t for (i in 0..<2) v[i + 14] = c[i + 6] - // rounds - for (r in 0..<16) { + repeat(16) { r -> val s = sigma[r % 10] - // column g(v, 0, 4, 8, 12, m[s[0]] xor c[s[1]], m[s[1]] xor c[s[0]]) g(v, 1, 5, 9, 13, m[s[2]] xor c[s[3]], m[s[3]] xor c[s[2]]) g(v, 2, 6, 10, 14, m[s[4]] xor c[s[5]], m[s[5]] xor c[s[4]]) g(v, 3, 7, 11, 15, m[s[6]] xor c[s[7]], m[s[7]] xor c[s[6]]) - // diagonal g(v, 0, 5, 10, 15, m[s[8]] xor c[s[9]], m[s[9]] xor c[s[8]]) g(v, 1, 6, 11, 12, m[s[10]] xor c[s[11]], m[s[11]] xor c[s[10]]) g(v, 2, 7, 8, 13, m[s[12]] xor c[s[13]], m[s[13]] xor c[s[12]]) g(v, 3, 4, 9, 14, m[s[14]] xor c[s[15]], m[s[15]] xor c[s[14]]) } - // finalization for (i in 0..7) { h[i] = h[i] xor v[i] xor v[i + 8] } } - // round function private fun g( v: ULongArray, a: Int, diff --git a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-512.kt b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-512.kt index 5d54f28..d1329fb 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-512.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-512.kt @@ -43,12 +43,25 @@ object `Blake-512` : HashFunction() { ) override fun hash(value: UByteArray): UByteArray { + val l = value.size.toULong() * 8UL val h = initial.copyOf() var t = 0UL - val l = value.size.toULong() * 8UL - // padding - val paddedValue = buildList { + val blocks = pad(value) + .chunked(128) { it.toUByteArray() } + for (block in blocks) { + t += minOf(l - t, 1024UL) + compress(h, block, t) + } + + return h.toUByteArray() + } + + private fun pad( + value: UByteArray, + ): UByteArray { + val l = value.size.toULong() * 8UL + return buildList { addAll(value) add(0x80U) while (size % 128 != 111) { @@ -58,56 +71,39 @@ object `Blake-512` : HashFunction() { repeat(8) { add(0x00U) } addAll(l.toUByteArray()) }.toUByteArray() - - // compress - val blocks = paddedValue - .chunked(128) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 1024UL) - - val m = block.toULongArray() - compress(h, m, t) - } - - return h.toUByteArray() } private fun compress( h: ULongArray, - m: ULongArray, + block: UByteArray, t: ULong, ) { - // initialization + val m = block.toULongArray() val v = ULongArray(16) for (i in 0..<8) v[i] = h[i] for (i in 0..<4) v[i + 8] = c[i] for (i in 0..<2) v[i + 12] = c[i + 4] xor t for (i in 0..<2) v[i + 14] = c[i + 6] - // rounds - for (r in 0..<16) { + repeat(16) { r -> val s = sigma[r % 10] - // column g(v, 0, 4, 8, 12, m[s[0]] xor c[s[1]], m[s[1]] xor c[s[0]]) g(v, 1, 5, 9, 13, m[s[2]] xor c[s[3]], m[s[3]] xor c[s[2]]) g(v, 2, 6, 10, 14, m[s[4]] xor c[s[5]], m[s[5]] xor c[s[4]]) g(v, 3, 7, 11, 15, m[s[6]] xor c[s[7]], m[s[7]] xor c[s[6]]) - // diagonal g(v, 0, 5, 10, 15, m[s[8]] xor c[s[9]], m[s[9]] xor c[s[8]]) g(v, 1, 6, 11, 12, m[s[10]] xor c[s[11]], m[s[11]] xor c[s[10]]) g(v, 2, 7, 8, 13, m[s[12]] xor c[s[13]], m[s[13]] xor c[s[12]]) g(v, 3, 4, 9, 14, m[s[14]] xor c[s[15]], m[s[15]] xor c[s[14]]) } - // finalization for (i in 0..7) { h[i] = h[i] xor v[i] xor v[i + 8] } } - // round function private fun g( v: ULongArray, a: Int, diff --git a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt index 9a2295a..0142418 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt @@ -36,65 +36,60 @@ class Blake2b( ) override fun hash(value: UByteArray): UByteArray { + val l = value.size.toULong() 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 { + val blocks = pad(value) + .chunked(128) { it.toUByteArray() } + for ((i, block) in blocks.withIndex()) { + t += minOf(l - t, 128UL) + compress(h, block, t, i == blocks.lastIndex) + } + + return h.toUByteArray(ByteOrder.LITTLE_ENDIAN).sliceArray(0.. val s = sigma[r % 10] - // column mix(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) mix(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) mix(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) mix(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) - // diagonal mix(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) mix(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) mix(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) } - // finalization for (i in 0..7) { h[i] = h[i] xor v[i] xor v[i + 8] } diff --git a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt index f05970e..b18c252 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt @@ -36,40 +36,40 @@ class Blake2s( ) override fun hash(value: UByteArray): UByteArray { + val l = value.size.toULong() val h = initial.copyOf() h[0] = h[0] xor (0x01010000U or bytes.toUInt()) var t = 0U - val l = value.size.toULong() - // padding - val paddedValue = buildList { + val blocks = pad(value) + .chunked(64) { it.toUByteArray() } + for ((i, block) in blocks.withIndex()) { + t += minOf(l - t, 64UL).toUInt() + compress(h, block, t, i == blocks.lastIndex) + } + + return h.toUByteArray(LITTLE_ENDIAN).sliceArray(0.. val s = sigma[r] - // column mix(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) mix(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) mix(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) mix(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) - // diagonal mix(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) mix(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) mix(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) } - // finalization for (i in 0..7) { h[i] = h[i] xor v[i] xor v[i + 8] }