diff --git a/.gitea/workflows/main.yaml b/.gitea/workflows/main.yaml deleted file mode 100644 index 4885477..0000000 --- a/.gitea/workflows/main.yaml +++ /dev/null @@ -1,36 +0,0 @@ -on: - push: - branches: - - main - -env: - INFENDRO__TOKEN: ${{ secrets.TOKEN }} - -jobs: - publish: - runs-on: linux - steps: - - uses: actions/checkout@v4 - - - uses: actions/cache/restore@v4 - with: - key: gradle - path: | - ~/.gradle/caches/ - ~/.gradle/wrapper/ - ~/.konan/ - - - uses: actions/setup-java@v4 - with: - java-version: '24' - distribution: 'temurin' - - - run: ./gradlew publish - - - uses: actions/cache/save@v4 - with: - key: gradle - path: | - ~/.gradle/caches/ - ~/.gradle/wrapper/ - ~/.konan/ diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml new file mode 100644 index 0000000..dad1306 --- /dev/null +++ b/.gitea/workflows/publish.yaml @@ -0,0 +1,47 @@ +on: + push: + branches: [ main ] + +jobs: + publish: + runs-on: linux + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '24' + distribution: 'temurin' + + - name: Cache Gradle + uses: actions/cache@v4 + with: + key: gradle-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: gradle + path: | + ~/.gradle/caches/ + ~/.gradle/wrapper/ + + - name: Cache Konan + uses: actions/cache@v4 + with: + key: konan-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: konan + path: | + ~/.konan/ + + - name: Cache Node + uses: actions/cache@v4 + with: + key: node-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: node + path: | + ~/.gradle/nodejs + ~/.gradle/yarn + + - name: Publish + run: ./gradlew publish + env: + INFENDRO__TOKEN: ${{ secrets.TOKEN }} diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml new file mode 100644 index 0000000..bce9e35 --- /dev/null +++ b/.gitea/workflows/test.yaml @@ -0,0 +1,28 @@ +on: + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: linux + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: '24' + distribution: 'temurin' + + - name: Cache Gradle + uses: actions/cache@v4 + with: + key: gradle-${{ hashFiles('**/libs.versions.toml') }} + restore-keys: gradle + path: | + ~/.gradle/caches/ + ~/.gradle/wrapper/ + + - name: Test + run: ./gradlew jvmTest diff --git a/README.md b/README.md index 61e9815..0f8f260 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # hash-kt -`hash-kt` is a Kotlin Multiplatform library that provides common cryptographic hash functions. +`hash-kt` is a Kotlin Multiplatform library that provides common [Cryptographic Hash Functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function). -Supported hash functions: +Supported algorithms: - MD5 - SHA-1 - SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512) @@ -11,15 +11,6 @@ Supported hash functions: - Blake (Blake-224, Blake-256, Blake-384, Blake-512) - Blake2 (Blake2s, Blake2b) -## Targets - -| Target | Status | -|------------------|---------------| -| JVM | Supported | -| JavaScript | Supported | -| Native (Linux) | Supported | -| Native (Windows) | Not Supported | - ## Installation Add the following to your `build.gradle.kts`. @@ -30,19 +21,16 @@ repositories { } dependencies { - implementation("com.infendro:hash:1.3.2") + implementation("com.infendro:hash:1.5.0") } ``` ## Usage ```kotlin -import com.infendro.hash.sha2.`SHA-256` - fun main() { // hash some value using SHA-256 - val value = "Hello World!" - .encodeToByteArray().asUByteArray() + val value = "Hello World!".encodeToByteArray() val hash = `SHA-256`.hash(value) } ``` diff --git a/build.gradle.kts b/build.gradle.kts index 3611921..f427d4c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,11 @@ +@file:OptIn(ExperimentalWasmDsl::class) + import com.infendro.plugin.infendro import com.infendro.plugin.token +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl group = "com.infendro" -version = "1.4.0" +version = "1.5.0" plugins { alias(libs.plugins.infendro) @@ -12,10 +15,14 @@ plugins { kotlin { jvm() - js { - nodejs() - } linuxX64() + linuxArm64() + mingwX64() + macosX64() + macosArm64() + js { nodejs() } + wasmJs { nodejs() } + wasmWasi { nodejs() } repositories { infendro() @@ -24,7 +31,7 @@ kotlin { sourceSets { commonMain.dependencies { - implementation(libs.bytearray) + implementation(libs.bytes) } commonTest.dependencies { implementation(libs.test) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2774958..ed30e83 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] -infendro = "1.0.0" -kotlin = "2.2.21" -bytearray = "1.2.4" +infendro = "1.1.0" +kotlin = "2.3.0" +bytes = "1.3.3" [plugins] infendro = { id = "com.infendro.plugin", version.ref = "infendro" } multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } [libraries] -bytearray = { module = "com.infendro:bytearray", version.ref = "bytearray" } +bytes = { module = "com.infendro:bytes", version.ref = "bytes" } test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } diff --git a/src/commonMain/kotlin/com/infendro/hash/HashFunction.kt b/src/commonMain/kotlin/com/infendro/hash/HashFunction.kt index 34e40d9..154aebd 100644 --- a/src/commonMain/kotlin/com/infendro/hash/HashFunction.kt +++ b/src/commonMain/kotlin/com/infendro/hash/HashFunction.kt @@ -7,7 +7,20 @@ interface HashFunction { val block: Int - fun hash( - value: UByteArray, - ): UByteArray + fun hashInto(value: ByteArray, destination: ByteArray) + + fun hashInto(value: ByteArray, destination: UByteArray) = + hashInto(value, destination.asByteArray()) + + fun hashInto(value: UByteArray, destination: UByteArray) = + hashInto(value.asByteArray(), destination.asByteArray()) + + fun hashInto(value: UByteArray, destination: ByteArray) = + hashInto(value.asByteArray(), destination) + + fun hash(value: ByteArray): ByteArray = + ByteArray(bytes).also { hashInto(value, it) } + + fun hash(value: UByteArray): UByteArray = + UByteArray(bytes).also { hashInto(value, it) } } 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 68d02ef..eec2225 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-224.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-224.kt @@ -1,8 +1,9 @@ package com.infendro.hash.blake -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +import com.infendro.bytes.intarray.copyInto +import com.infendro.bytes.ulong.copyInto import com.infendro.hash.HashFunction +import com.infendro.hash.util.align object `Blake-224` : HashFunction { override val bytes: Int @@ -16,108 +17,31 @@ object `Blake-224` : HashFunction { 0x3070dd17U, 0xf70e5939U, 0xffc00b31U, 0x68581511U, 0x64f98fa7U, 0xbefa4fa4U, - ) + ).asIntArray() - private val c = uintArrayOf( - 0x243f6a88U, 0x85a308d3U, - 0x13198a2eU, 0x03707344U, - 0xa4093822U, 0x299f31d0U, - 0x082efa98U, 0xec4e6c89U, - 0x452821e6U, 0x38d01377U, - 0xbe5466cfU, 0x34e90c6cU, - 0xc0ac29b7U, 0xc97c50ddU, - 0x3f84d5b5U, 0xb5470917U, - ) - - 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 l = value.size.toULong() * 8UL + override fun hashInto(value: ByteArray, destination: ByteArray) { + val length = value.size.toULong() * 8UL + val input = pad(value) val h = initial.copyOf() + val m = IntArray(16) + val v = IntArray(16) var t = 0U - val blocks = pad(value) - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 512UL).toUInt() - compress(h, block, t) + for (i in input.indices step block) { + t += minOf(length - t, 512UL).toUInt() + `Blake-256`.compress(h, input, i, m, v, t) } - - return h.sliceArray(0..6).toUByteArray() + h.copyInto(destination, endIndex = 7) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 64 != 56) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() - } + private fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL - private fun compress( - h: UIntArray, - block: UByteArray, - t: UInt, - ) { - 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] - - repeat(14) { r -> - val s = sigma[r % 10] - - 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]]) - - 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]]) - } - - for (i in 0..7) { - h[i] = h[i] xor v[i] xor v[i + 8] - } - } - - private fun g( - v: UIntArray, - a: Int, - b: Int, - c: Int, - d: Int, - x: UInt, - y: UInt, - ) { - v[a] += v[b] + x - v[d] = (v[d] xor v[a]).rotateRight(16) - v[c] += v[d] - v[b] = (v[b] xor v[c]).rotateRight(12) - v[a] += v[b] + y - v[d] = (v[d] xor v[a]).rotateRight(8) - v[c] += v[d] - v[b] = (v[b] xor v[c]).rotateRight(7) + val size = (value.size + 9).align(block) + val result = ByteArray(size) + value.copyInto(result) + result[value.size] = 0x80U.toByte() + length.copyInto(result, result.size - 8) + return result } } 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 f55bf6e..8ef894e 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-256.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-256.kt @@ -1,8 +1,10 @@ package com.infendro.hash.blake -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +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.align object `Blake-256` : HashFunction { override val bytes: Int @@ -16,7 +18,7 @@ object `Blake-256` : HashFunction { 0x3c6ef372U, 0xa54ff53aU, 0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U, - ) + ).asIntArray() private val c = uintArrayOf( 0x243f6a88U, 0x85a308d3U, @@ -27,7 +29,7 @@ object `Blake-256` : HashFunction { 0xbe5466cfU, 0x34e90c6cU, 0xc0ac29b7U, 0xc97c50ddU, 0x3f84d5b5U, 0xb5470917U, - ) + ).asIntArray() private val sigma = arrayOf( intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), @@ -42,46 +44,38 @@ object `Blake-256` : HashFunction { intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), ) - override fun hash(value: UByteArray): UByteArray { - val l = value.size.toULong() * 8UL + override fun hashInto(value: ByteArray, destination: ByteArray) { + val length = value.size.toULong() * 8UL + val input = pad(value) val h = initial.copyOf() + val m = IntArray(16) + val v = IntArray(16) var t = 0U - val blocks = pad(value) - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 512UL).toUInt() - compress(h, block, t) + for (i in input.indices step block) { + t += minOf(length - t, 512UL).toUInt() + compress(h, input, i, m, v, t) } - - return h.toUByteArray() + h.copyInto(destination) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 64 != 55) { - add(0x00U) - } - add(0x01U) - addAll(l.toUByteArray()) - }.toUByteArray() + private fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL + + val size = (value.size + 10).align(block) + val result = ByteArray(size) + value.copyInto(result) + result[value.size] = 0x80U.toByte() + result[result.size - 9] = 0x01 + length.copyInto(result, result.size - 8) + return result } - private fun compress( - h: UIntArray, - block: UByteArray, - t: UInt, - ) { - val m = block.toUIntArray() - val v = UIntArray(16) + internal fun compress(h: IntArray, value: ByteArray, offset: Int, m: IntArray, v: IntArray, t: UInt) { + value.copyInto(m, startIndex = offset, endIndex = offset + block) 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 + 12] = c[i + 4] xor t.toInt() for (i in 0..<2) v[i + 14] = c[i + 6] repeat(14) { r -> @@ -98,20 +92,12 @@ object `Blake-256` : HashFunction { g(v, 3, 4, 9, 14, m[s[14]] xor c[s[15]], m[s[15]] xor c[s[14]]) } - for (i in 0..7) { + for (i in 0..<8) { h[i] = h[i] xor v[i] xor v[i + 8] } } - private fun g( - v: UIntArray, - a: Int, - b: Int, - c: Int, - d: Int, - x: UInt, - y: UInt, - ) { + private fun g(v: IntArray, a: Int, b: Int, c: Int, d: Int, x: Int, y: Int) { v[a] += v[b] + x v[d] = (v[d] xor v[a]).rotateRight(16) v[c] += v[d] 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 47f9bcb..588710b 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-384.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-384.kt @@ -1,8 +1,9 @@ package com.infendro.hash.blake -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toULongArray +import com.infendro.bytes.longarray.copyInto +import com.infendro.bytes.ulong.copyInto import com.infendro.hash.HashFunction +import com.infendro.hash.util.align object `Blake-384` : HashFunction { override val bytes: Int @@ -16,108 +17,31 @@ object `Blake-384` : HashFunction { 0x9159015a3070dd17U, 0x152fecd8f70e5939U, 0x67332667ffc00b31U, 0x8eb44a8768581511U, 0xdb0c2e0d64f98fa7U, 0x47b5481dbefa4fa4U, - ) + ).asLongArray() - private val c = ulongArrayOf( - 0x243f6a8885a308d3UL, 0x13198a2e03707344UL, - 0xa4093822299f31d0UL, 0x082efa98ec4e6c89UL, - 0x452821e638d01377UL, 0xbe5466cf34e90c6cUL, - 0xc0ac29b7c97c50ddUL, 0x3f84d5b5b5470917UL, - 0x9216d5d98979fb1bUL, 0xd1310ba698dfb5acUL, - 0x2ffd72dbd01adfb7UL, 0xb8e1afed6a267e96UL, - 0xba7c9045f12c7f99UL, 0x24a19947b3916cf7UL, - 0x0801f2e2858efc16UL, 0x636920d871574e69UL, - ) - - 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 l = value.size.toULong() * 8UL + override fun hashInto(value: ByteArray, destination: ByteArray) { + val length = value.size.toULong() * 8UL + val input = pad(value) val h = initial.copyOf() + val m = LongArray(16) + val v = LongArray(16) var t = 0UL - val blocks = pad(value) - .chunked(128) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 1024UL) - compress(h, block, t) + for (i in input.indices step block) { + t += minOf(length - t, 1024UL) + `Blake-512`.compress(h, input, i, m, v, t) } - - return h.sliceArray(0..5).toUByteArray() + h.copyInto(destination, endIndex = 6) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 128 != 120) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() - } + private fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL - private fun compress( - h: ULongArray, - block: UByteArray, - t: ULong, - ) { - 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] - - repeat(16) { r -> - val s = sigma[r % 10] - - 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]]) - - 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]]) - } - - for (i in 0..7) { - h[i] = h[i] xor v[i] xor v[i + 8] - } - } - - private fun g( - v: ULongArray, - a: Int, - b: Int, - c: Int, - d: Int, - x: ULong, - y: ULong, - ) { - v[a] += v[b] + x - v[d] = (v[d] xor v[a]).rotateRight(32) - v[c] += v[d] - v[b] = (v[b] xor v[c]).rotateRight(25) - v[a] += v[b] + y - v[d] = (v[d] xor v[a]).rotateRight(16) - v[c] += v[d] - v[b] = (v[b] xor v[c]).rotateRight(11) + val size = (value.size + 17).align(block) + val result = ByteArray(size) + value.copyInto(result) + result[value.size] = 0x80U.toByte() + length.copyInto(result, result.size - 8) + return result } } 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 9a1821c..7974370 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake/Blake-512.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake/Blake-512.kt @@ -1,8 +1,10 @@ package com.infendro.hash.blake -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toULongArray +import com.infendro.bytes.bytearray.copyInto +import com.infendro.bytes.longarray.copyInto +import com.infendro.bytes.ulong.copyInto import com.infendro.hash.HashFunction +import com.infendro.hash.util.align object `Blake-512` : HashFunction { override val bytes: Int @@ -16,7 +18,7 @@ object `Blake-512` : HashFunction { 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, - ) + ).asLongArray() private val c = ulongArrayOf( 0x243f6a8885a308d3UL, 0x13198a2e03707344UL, @@ -27,7 +29,7 @@ object `Blake-512` : HashFunction { 0x2ffd72dbd01adfb7UL, 0xb8e1afed6a267e96UL, 0xba7c9045f12c7f99UL, 0x24a19947b3916cf7UL, 0x0801f2e2858efc16UL, 0x636920d871574e69UL, - ) + ).asLongArray() private val sigma = arrayOf( intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), @@ -42,47 +44,38 @@ object `Blake-512` : HashFunction { intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), ) - override fun hash(value: UByteArray): UByteArray { - val l = value.size.toULong() * 8UL + override fun hashInto(value: ByteArray, destination: ByteArray) { + val length = value.size.toULong() * 8UL + val input = pad(value) val h = initial.copyOf() + val m = LongArray(16) + val v = LongArray(16) var t = 0UL - val blocks = pad(value) - .chunked(128) { it.toUByteArray() } - for (block in blocks) { - t += minOf(l - t, 1024UL) - compress(h, block, t) + for (i in input.indices step block) { + t += minOf(length - t, 1024UL) + compress(h, input, i, m, v, t) } - - return h.toUByteArray() + h.copyInto(destination) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 128 != 111) { - add(0x00U) - } - add(0x01U) - repeat(8) { add(0x00U) } - addAll(l.toUByteArray()) - }.toUByteArray() + private fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL + + val size = (value.size + 18).align(block) + val result = ByteArray(size) + value.copyInto(result) + result[value.size] = 0x80U.toByte() + result[result.size - 17] = 0x01 + length.copyInto(result, result.size - 8) + return result } - private fun compress( - h: ULongArray, - block: UByteArray, - t: ULong, - ) { - val m = block.toULongArray() - val v = ULongArray(16) + internal fun compress(h: LongArray, value: ByteArray, offset: Int, m: LongArray, v: LongArray, t: ULong) { + value.copyInto(m, startIndex = offset, endIndex = offset + block) 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 + 12] = c[i + 4] xor t.toLong() for (i in 0..<2) v[i + 14] = c[i + 6] repeat(16) { r -> @@ -99,20 +92,12 @@ object `Blake-512` : HashFunction { g(v, 3, 4, 9, 14, m[s[14]] xor c[s[15]], m[s[15]] xor c[s[14]]) } - for (i in 0..7) { + for (i in 0..<8) { h[i] = h[i] xor v[i] xor v[i + 8] } } - private fun g( - v: ULongArray, - a: Int, - b: Int, - c: Int, - d: Int, - x: ULong, - y: ULong, - ) { + private fun g(v: LongArray, a: Int, b: Int, c: Int, d: Int, x: Long, y: Long) { v[a] += v[b] + x v[d] = (v[d] xor v[a]).rotateRight(32) v[c] += v[d] diff --git a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt index d9e27b2..7ab685c 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2b.kt @@ -1,9 +1,10 @@ package com.infendro.hash.blake2 -import com.infendro.bytearray.ByteOrder -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toULongArray +import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN +import com.infendro.bytes.bytearray.copyInto +import com.infendro.bytes.longarray.toByteArray import com.infendro.hash.HashFunction +import com.infendro.hash.util.align class Blake2b( override val bytes: Int, @@ -20,7 +21,7 @@ class Blake2b( 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, - ) + ).asLongArray() private val sigma = arrayOf( intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), @@ -35,45 +36,42 @@ class Blake2b( intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), ) - override fun hash(value: UByteArray): UByteArray { - val l = value.size.toULong() + override fun hashInto(value: ByteArray, destination: ByteArray) { + val length = value.size.toULong() + val input = pad(value) val h = initial.copyOf() - h[0] = h[0] xor (0x01010000UL or bytes.toULong()) + h[0] = h[0] xor (0x01010000L or bytes.toLong()) + val m = LongArray(16) + val v = LongArray(16) var t = 0UL - 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) + for (i in input.indices step block) { + t += minOf(length - t, 128UL) + compress(h, input, i, m, v, t, t < 1024UL) } - - return h.toUByteArray(ByteOrder.LITTLE_ENDIAN).sliceArray(0.. @@ -90,20 +88,12 @@ class Blake2b( mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) } - for (i in 0..7) { + for (i in 0..<8) { h[i] = h[i] xor v[i] xor v[i + 8] } } - private fun mix( - v: ULongArray, - a: Int, - b: Int, - c: Int, - d: Int, - x: ULong, - y: ULong, - ) { + private fun mix(v: LongArray, a: Int, b: Int, c: Int, d: Int, x: Long, y: Long) { v[a] += v[b] + x v[d] = (v[d] xor v[a]).rotateRight(32) v[c] += v[d] diff --git a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt index 3b54b4c..590e38e 100644 --- a/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt +++ b/src/commonMain/kotlin/com/infendro/hash/blake2/Blake2s.kt @@ -1,9 +1,10 @@ package com.infendro.hash.blake2 -import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN +import com.infendro.bytes.bytearray.copyInto +import com.infendro.bytes.intarray.toByteArray import com.infendro.hash.HashFunction +import com.infendro.hash.util.align class Blake2s( override val bytes: Int, @@ -20,7 +21,7 @@ class Blake2s( 0x3c6ef372U, 0xa54ff53aU, 0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U, - ) + ).asIntArray() private val sigma = arrayOf( intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), @@ -35,46 +36,42 @@ class Blake2s( intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), ) - override fun hash(value: UByteArray): UByteArray { - val l = value.size.toULong() + override fun hashInto(value: ByteArray, destination: ByteArray) { + val length = value.size.toULong() + val input = pad(value) val h = initial.copyOf() - h[0] = h[0] xor (0x01010000U or bytes.toUInt()) + h[0] = h[0] xor (0x01010000 or bytes) + val m = IntArray(16) + val v = IntArray(16) var t = 0U - 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) + for (i in input.indices step block) { + t += minOf(length - t, 64UL).toUInt() + compress(h, input, i, m, v, t, t < 1024UL) } - - return h.toUByteArray(LITTLE_ENDIAN).sliceArray(0.. @@ -91,20 +88,12 @@ class Blake2s( mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) } - for (i in 0..7) { + for (i in 0..<8) { h[i] = h[i] xor v[i] xor v[i + 8] } } - private fun mix( - v: UIntArray, - a: Int, - b: Int, - c: Int, - d: Int, - x: UInt, - y: UInt, - ) { + private fun mix(v: IntArray, a: Int, b: Int, c: Int, d: Int, x: Int, y: Int) { v[a] += v[b] + x v[d] = (v[d] xor v[a]).rotateRight(16) v[c] += v[d] diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/Keccak.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/Keccak.kt index 15a0cb2..91520c0 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/Keccak.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/Keccak.kt @@ -1,16 +1,21 @@ package com.infendro.hash.keccak -import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toULongArray +import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN +import com.infendro.bytes.bytearray.copyInto +import com.infendro.bytes.long.copyInto import com.infendro.hash.HashFunction -import kotlin.math.min +import com.infendro.hash.util.align -abstract class Keccak( +open class Keccak( override val bytes: Int, private val rate: Int, - private val domain: UByte, + private val domain: Byte, ) : HashFunction { + init { + require(bytes > 0) + require(rate in 8..192 step 8) + } + override val block: Int get() = rate @@ -21,7 +26,7 @@ abstract class Keccak( 0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL, 0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL, 0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL, - ) + ).asLongArray() private val rotation = arrayOf( intArrayOf(0, 36, 3, 41, 18), @@ -31,93 +36,81 @@ abstract class Keccak( intArrayOf(27, 20, 39, 8, 14), ) - override fun hash( - value: UByteArray, - ): UByteArray { - val state = ULongArray(25) + override fun hashInto(value: ByteArray, destination: ByteArray) { + val input = pad(value) + val state = LongArray(25) + val w = LongArray(block / 8) + val b = LongArray(25) + val c = LongArray(5) + val d = LongArray(5) - val blocks = pad(value) - .chunked(rate) { it.toUByteArray() } - for (block in blocks) { - absorb(state, block) + for (i in input.indices step block) { + absorb(state, input, i, w) + permute(state, b, c, d) } - - return squeeze(state) + squeeze(state, b, c, d, destination) } - private fun pad( - value: UByteArray, - ): UByteArray { - return buildList { - addAll(value) - add(domain) - while ((size % rate) != (rate - 1)) { - add(0x00U) - } - add(0x80U) - }.toUByteArray() + private fun pad(value: ByteArray): ByteArray { + val size = (value.size + 2).align(block) + val result = ByteArray(size) + value.copyInto(result) + result[value.size] = domain + result[result.lastIndex] = 0x80U.toByte() + return result } - private fun absorb( - state: ULongArray, - block: UByteArray, - ) { - val numbers = block.toULongArray(LITTLE_ENDIAN) - for ((i, number) in numbers.withIndex()) { - state[i] = state[i] xor number - } - permute(state) - } - - private fun permute( - a: ULongArray, - ) { - val b = ULongArray(25) - val c = ULongArray(5) - val d = ULongArray(5) - - repeat(24) { round -> - // θ - for (x in 0..4) { - c[x] = a[x] xor a[x + 5] xor a[x + 10] xor a[x + 15] xor a[x + 20] - } - for (x in 0..4) { - d[x] = c[(x + 4) % 5] xor c[(x + 1) % 5].rotateLeft(1) - } - for (x in 0..4) for (y in 0..4) { - a[x + 5 * y] = a[x + 5 * y] xor d[x] - } - - // ρ and π - for (x in 0..4) for (y in 0..4) { - b[y + 5 * ((2 * x + 3 * y) % 5)] = a[x + 5 * y].rotateLeft(rotation[x][y]) - } - - // χ - for (x in 0..4) for (y in 0..4) { - a[x + 5 * y] = b[x + 5 * y] xor ((b[((x + 1) % 5) + 5 * y].inv()) and b[((x + 2) % 5) + 5 * y]) - } - - // ι - a[0] = a[0] xor rc[round] + private fun absorb(state: LongArray, value: ByteArray, offset: Int, w: LongArray) { + value.copyInto(w, startIndex = offset, endIndex = offset + block, order = LITTLE_ENDIAN) + for (i in w.indices) { + state[i] = state[i] xor w[i] } } - private fun squeeze( - state: ULongArray, - ): UByteArray { - return buildList { - var i = 0 - while (size < bytes) { - if (i == rate / 8) { - permute(state) - i = 0 - } - addAll( - state[i++].toUByteArray(LITTLE_ENDIAN) - .sliceArray(0.. + // θ + for (x in 0..4) { + c[x] = a[x] xor a[x + 5] xor a[x + 10] xor a[x + 15] xor a[x + 20] + } + for (x in 0..4) { + d[x] = c[(x + 4) % 5] xor c[(x + 1) % 5].rotateLeft(1) + } + for (x in 0..4) for (y in 0..4) { + a[x + 5 * y] = a[x + 5 * y] xor d[x] + } + + // ρ and π + for (x in 0..4) for (y in 0..4) { + b[y + 5 * ((2 * x + 3 * y) % 5)] = a[x + 5 * y].rotateLeft(rotation[x][y]) + } + + // χ + for (x in 0..4) for (y in 0..4) { + a[x + 5 * y] = b[x + 5 * y] xor ((b[((x + 1) % 5) + 5 * y].inv()) and b[((x + 2) % 5) + 5 * y]) + } + + // ι + a[0] = a[0] xor rc[round] } } diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt index b538483..369b3c5 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt @@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3 import com.infendro.hash.keccak.Keccak -object `SHA3-224` : Keccak(28, 144, 0x06U) +object `SHA3-224` : Keccak(28, 144, 0x06) diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt index 0980697..1b132ab 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt @@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3 import com.infendro.hash.keccak.Keccak -object `SHA3-256` : Keccak(32, 136, 0x06U) +object `SHA3-256` : Keccak(32, 136, 0x06) diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt index 5ee5f5d..e0dc589 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt @@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3 import com.infendro.hash.keccak.Keccak -object `SHA3-384` : Keccak(48, 104, 0x06U) +object `SHA3-384` : Keccak(48, 104, 0x06) diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt index 51efc8d..c0f8207 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt @@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3 import com.infendro.hash.keccak.Keccak -object `SHA3-512` : Keccak(64, 72, 0x06U) +object `SHA3-512` : Keccak(64, 72, 0x06) diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt index 4161707..c154631 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt @@ -4,4 +4,4 @@ import com.infendro.hash.keccak.Keccak class SHAKE128( bytes: Int, -) : Keccak(bytes, 168, 0x1FU) +) : Keccak(bytes, 168, 0x1F) diff --git a/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt b/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt index c18be12..46a9107 100644 --- a/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt +++ b/src/commonMain/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt @@ -4,4 +4,4 @@ import com.infendro.hash.keccak.Keccak class SHAKE256( bytes: Int, -) : Keccak(bytes, 136, 0x1FU) +) : Keccak(bytes, 136, 0x1F) diff --git a/src/commonMain/kotlin/com/infendro/hash/md/MD5.kt b/src/commonMain/kotlin/com/infendro/hash/md/MD5.kt index 132ed5c..846ed1c 100644 --- a/src/commonMain/kotlin/com/infendro/hash/md/MD5.kt +++ b/src/commonMain/kotlin/com/infendro/hash/md/MD5.kt @@ -1,9 +1,11 @@ package com.infendro.hash.md -import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN +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.align object MD5 : HashFunction { override val bytes: Int @@ -15,18 +17,7 @@ object MD5 : HashFunction { private val initial = uintArrayOf( 0x67452301U, 0xefcdab89U, 0x98badcfeU, 0x10325476U, - ) - - private val shifts = intArrayOf( - 7, 12, 17, 22, 7, 12, 17, 22, - 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, - 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, - 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, - 6, 10, 15, 21, 6, 10, 15, 21, - ) + ).asIntArray() private val c = uintArrayOf( 0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU, @@ -45,54 +36,57 @@ object MD5 : HashFunction { 0x655b59c3U, 0x8f0ccc92U, 0xffeff47dU, 0x85845dd1U, 0x6fa87e4fU, 0xfe2ce6e0U, 0xa3014314U, 0x4e0811a1U, 0xf7537e82U, 0xbd3af235U, 0x2ad7d2bbU, 0xeb86d391U, + ).asIntArray() + + private val shifts = intArrayOf( + 7, 12, 17, 22, 7, 12, 17, 22, + 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, + 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, + 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, + 6, 10, 15, 21, 6, 10, 15, 21, ) - override fun hash( - value: UByteArray, - ): UByteArray { + override fun hashInto(value: ByteArray, destination: ByteArray) { + val input = pad(value) val h = initial.copyOf() + val w = IntArray(16) + val v = IntArray(4) - val blocks = pad(value) - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - process(h, block) + for (i in input.indices step block) { + process(h, input, i, w, v) } - - return h.toUByteArray(LITTLE_ENDIAN) + h.copyInto(destination, order = LITTLE_ENDIAN) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 64 != 56) { - add(0x00U) - } - addAll(l.toUByteArray(LITTLE_ENDIAN)) - }.toUByteArray() + private fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL + + val size = (value.size + 9).align(block) + val result = ByteArray(size) + value.copyInto(result) + result[value.size] = 0x80U.toByte() + length.copyInto(result, result.size - 8, order = LITTLE_ENDIAN) + return result } - private fun process( - h: UIntArray, - block: UByteArray, - ) { - val w = block.toUIntArray(LITTLE_ENDIAN) - val v = h.copyOf() + private fun process(h: IntArray, value: ByteArray, offset: Int, w: IntArray, v: IntArray) { + value.copyInto(w, startIndex = offset, endIndex = offset + block, order = LITTLE_ENDIAN) + h.copyInto(v) repeat(64) { i -> var f = when (i) { - in 0..15 -> (v[1] and v[2]) or (v[1].inv() and v[3]) - in 16..31 -> (v[3] and v[1]) or (v[3].inv() and v[2]) - in 32..47 -> v[1] xor v[2] xor v[3] + in 0..<16 -> (v[1] and v[2]) or (v[1].inv() and v[3]) + in 16..<32 -> (v[3] and v[1]) or (v[3].inv() and v[2]) + in 32..<48 -> v[1] xor v[2] xor v[3] else -> v[2] xor (v[1] or v[3].inv()) } val g = when (i) { - in 0..15 -> i - in 16..31 -> (5 * i + 1) % 16 - in 32..47 -> (3 * i + 5) % 16 + in 0..<16 -> i + in 16..<32 -> (5 * i + 1) % 16 + in 32..<48 -> (3 * i + 5) % 16 else -> (7 * i) % 16 } f += v[0] + c[i] + w[g] @@ -102,7 +96,7 @@ object MD5 : HashFunction { v[1] += f.rotateLeft(shifts[i]) } - for (i in 0..3) { + for (i in 0..<4) { h[i] += v[i] } } diff --git a/src/commonMain/kotlin/com/infendro/hash/sha1/SHA1.kt b/src/commonMain/kotlin/com/infendro/hash/sha1/SHA1.kt index 236b0b5..7d1b356 100644 --- a/src/commonMain/kotlin/com/infendro/hash/sha1/SHA1.kt +++ b/src/commonMain/kotlin/com/infendro/hash/sha1/SHA1.kt @@ -1,8 +1,10 @@ package com.infendro.hash.sha1 -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +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.align object SHA1 : HashFunction { override val bytes: Int @@ -15,48 +17,42 @@ object SHA1 : HashFunction { 0x67452301U, 0xefcdaB89U, 0x98badcfeU, 0x10325476U, 0xc3d2e1f0U, - ) + ).asIntArray() - override fun hash( - value: UByteArray, - ): UByteArray { + 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) - val blocks = pad(value) - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - process(h, block) + for (i in input.indices step block) { + process(h, input, i, w, v) } - - return h.toUByteArray() + h.copyInto(destination) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 64 != 56) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() + private fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL + + val size = (value.size + 9).align(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: UIntArray, - block: UByteArray, - ) { - val w = buildList { - addAll(block.toUIntArray()) - for (i in 16..79) { - val word = (get(i - 3) xor get(i - 8) xor get(i - 14) xor get(i - 16)).rotateLeft(1) - add(word) - } - }.toUIntArray() - val v = h.copyOf() + 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) { @@ -65,13 +61,7 @@ object SHA1 : HashFunction { 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 k = when (i) { - in 0..<20 -> 0x5a827999U - in 20..<40 -> 0x6ed9eba1U - in 40..<60 -> 0x8f1bbcdcU - else -> 0xca62c1d6U - } - val temp = v[0].rotateLeft(5) + f + v[4] + k + w[i] + 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) @@ -79,7 +69,7 @@ object SHA1 : HashFunction { v[0] = temp } - for (i in 0..4) { + for (i in 0..<5) { h[i] += v[i] } } diff --git a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-224.kt b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-224.kt index d08ed67..d2807b6 100644 --- a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-224.kt +++ b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-224.kt @@ -1,7 +1,6 @@ package com.infendro.hash.sha2 -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +import com.infendro.bytes.intarray.copyInto import com.infendro.hash.HashFunction object `SHA-224` : HashFunction { @@ -16,81 +15,17 @@ object `SHA-224` : HashFunction { 0x3070dd17U, 0xf70e5939U, 0xffc00b31U, 0x68581511U, 0x64f98fa7U, 0xbefa4fa4U, - ) + ).asIntArray() - private val c = uintArrayOf( - 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, - 0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U, - 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, - 0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U, - 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U, - 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U, - 0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U, - 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U, - ) - - override fun hash( - value: UByteArray, - ): UByteArray { + override fun hashInto(value: ByteArray, destination: ByteArray) { + val input = `SHA-256`.pad(value) val h = initial.copyOf() + val w = IntArray(64) + val v = IntArray(8) - val blocks = pad(value) - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - process(h, block) - } - - 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) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() - } - - private fun process( - h: UIntArray, - block: UByteArray, - ) { - val w = buildList { - addAll(block.toUIntArray()) - for (i in 16..63) { - val s0 = get(i - 15).rotateRight(7) xor get(i - 15).rotateRight(18) xor (get(i - 15) shr 3) - val s1 = get(i - 2).rotateRight(17) xor get(i - 2).rotateRight(19) xor (get(i - 2) shr 10) - add(get(i - 16) + s0 + get(i - 7) + s1) - } - }.toUIntArray() - val v = h.copyOf() - - repeat(64) { i -> - val s0 = v[0].rotateRight(2) xor v[0].rotateRight(13) xor v[0].rotateRight(22) - val s1 = v[4].rotateRight(6) xor v[4].rotateRight(11) xor v[4].rotateRight(25) - val ch = (v[4] and v[5]) xor (v[4].inv() and v[6]) - val temp1 = v[7] + s1 + ch + this.c[i] + w[i] - val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2]) - val temp2 = s0 + maj - - v[7] = v[6] - v[6] = v[5] - v[5] = v[4] - v[4] = v[3] + temp1 - v[3] = v[2] - v[2] = v[1] - v[1] = v[0] - v[0] = temp1 + temp2 - } - - for (i in 0..7) { - h[i] += v[i] + for (i in input.indices step block) { + `SHA-256`.process(h, input, i, w, v) } + h.copyInto(destination, endIndex = 7) } } diff --git a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-256.kt b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-256.kt index b47a39c..db53bef 100644 --- a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-256.kt +++ b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-256.kt @@ -1,8 +1,10 @@ package com.infendro.hash.sha2 -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toUIntArray +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.align object `SHA-256` : HashFunction { override val bytes: Int @@ -16,7 +18,7 @@ object `SHA-256` : HashFunction { 0x3c6ef372U, 0xa54ff53aU, 0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U, - ) + ).asIntArray() private val c = uintArrayOf( 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, @@ -27,49 +29,39 @@ object `SHA-256` : HashFunction { 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U, - ) + ).asIntArray() - override fun hash( - value: UByteArray, - ): UByteArray { + override fun hashInto(value: ByteArray, destination: ByteArray) { + val input = pad(value) val h = initial.copyOf() + val w = IntArray(64) + val v = IntArray(8) - val blocks = pad(value) - .chunked(64) { it.toUByteArray() } - for (block in blocks) { - process(h, block) + for (i in input.indices step block) { + process(h, input, i, w, v) } - - return h.toUByteArray() + h.copyInto(destination) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 64 != 56) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() + internal fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL + + val size = (value.size + 9).align(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: UIntArray, - block: UByteArray, - ) { - val w = buildList { - addAll(block.toUIntArray()) - for (i in 16..63) { - val s0 = get(i - 15).rotateRight(7) xor get(i - 15).rotateRight(18) xor (get(i - 15) shr 3) - val s1 = get(i - 2).rotateRight(17) xor get(i - 2).rotateRight(19) xor (get(i - 2) shr 10) - add(get(i - 16) + s0 + get(i - 7) + s1) - } - }.toUIntArray() - val v = h.copyOf() + internal fun process(h: IntArray, value: ByteArray, offset: Int, w: IntArray, v: IntArray) { + value.copyInto(w, startIndex = offset, endIndex = offset + block) + for (i in 16..<64) { + val s0 = w[i - 15].rotateRight(7) xor w[i - 15].rotateRight(18) xor (w[i - 15] ushr 3) + val s1 = w[i - 2].rotateRight(17) xor w[i - 2].rotateRight(19) xor (w[i - 2] ushr 10) + w[i] = (w[i - 16] + s0 + w[i - 7] + s1) + } + h.copyInto(v) repeat(64) { i -> val s0 = v[0].rotateRight(2) xor v[0].rotateRight(13) xor v[0].rotateRight(22) @@ -89,7 +81,7 @@ object `SHA-256` : HashFunction { v[0] = temp1 + temp2 } - for (i in 0..7) { + for (i in 0..<8) { h[i] += v[i] } } diff --git a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-384.kt b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-384.kt index fb536cf..3d069e7 100644 --- a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-384.kt +++ b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-384.kt @@ -1,7 +1,6 @@ package com.infendro.hash.sha2 -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toULongArray +import com.infendro.bytes.longarray.copyInto import com.infendro.hash.HashFunction object `SHA-384` : HashFunction { @@ -16,93 +15,17 @@ object `SHA-384` : HashFunction { 0x9159015a3070dd17UL, 0x152fecd8f70e5939UL, 0x67332667ffc00b31UL, 0x8eb44a8768581511UL, 0xdb0c2e0d64f98fa7UL, 0x47b5481dbefa4fa4UL, - ) + ).asLongArray() - private val c = ulongArrayOf( - 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, - 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL, - 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL, - 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL, - 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL, - 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL, - 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL, - 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, 0x06ca6351e003826fUL, 0x142929670a0e6e70UL, - 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL, - 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, 0x81c2c92e47edaee6UL, 0x92722c851482353bUL, - 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL, - 0xd192e819d6ef5218UL, 0xd69906245565a910UL, 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL, - 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL, - 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL, - 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL, - 0x90befffa23631e28UL, 0xa4506cebde82bde9UL, 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL, - 0xca273eceea26619cUL, 0xd186b8c721c0c207UL, 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL, - 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, 0x1b710b35131c471bUL, - 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL, - 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL, - ) - - override fun hash( - value: UByteArray, - ): UByteArray { + override fun hashInto(value: ByteArray, destination: ByteArray) { + val input = `SHA-512`.pad(value) val h = initial.copyOf() + val w = LongArray(80) + val v = LongArray(8) - val blocks = pad(value) - .chunked(128) { it.toUByteArray() } - for (block in blocks) { - process(h, block) - } - - 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) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() - } - - private fun process( - h: ULongArray, - block: UByteArray, - ) { - val w = buildList { - addAll(block.toULongArray()) - for (i in 16..79) { - val s0 = get(i - 15).rotateRight(1) xor get(i - 15).rotateRight(8) xor (get(i - 15) shr 7) - val s1 = get(i - 2).rotateRight(19) xor get(i - 2).rotateRight(61) xor (get(i - 2) shr 6) - add(get(i - 16) + s0 + get(i - 7) + s1) - } - }.toULongArray() - val v = h.copyOf() - - repeat(80) { i -> - val s0 = v[0].rotateRight(28) xor v[0].rotateRight(34) xor v[0].rotateRight(39) - val s1 = v[4].rotateRight(14) xor v[4].rotateRight(18) xor v[4].rotateRight(41) - val ch = (v[4] and v[5]) xor (v[4].inv() and v[6]) - val temp1 = v[7] + s1 + ch + this.c[i] + w[i] - val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2]) - val temp2 = s0 + maj - - v[7] = v[6] - v[6] = v[5] - v[5] = v[4] - v[4] = v[3] + temp1 - v[3] = v[2] - v[2] = v[1] - v[1] = v[0] - v[0] = temp1 + temp2 - } - - for (i in 0..7) { - h[i] += v[i] + for (i in input.indices step block) { + `SHA-512`.process(h, input, i, w, v) } + h.copyInto(destination, endIndex = 6) } } diff --git a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-512.kt b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-512.kt index c0dc89c..1dd84e0 100644 --- a/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-512.kt +++ b/src/commonMain/kotlin/com/infendro/hash/sha2/SHA-512.kt @@ -1,8 +1,10 @@ package com.infendro.hash.sha2 -import com.infendro.bytearray.toUByteArray -import com.infendro.bytearray.toULongArray +import com.infendro.bytes.bytearray.copyInto +import com.infendro.bytes.longarray.copyInto +import com.infendro.bytes.ulong.copyInto import com.infendro.hash.HashFunction +import com.infendro.hash.util.align object `SHA-512` : HashFunction { override val bytes: Int @@ -16,7 +18,7 @@ object `SHA-512` : HashFunction { 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, - ) + ).asLongArray() private val c = ulongArrayOf( 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, @@ -39,55 +41,45 @@ object `SHA-512` : HashFunction { 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, 0x1b710b35131c471bUL, 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL, 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL, - ) + ).asLongArray() - override fun hash( - value: UByteArray, - ): UByteArray { + override fun hashInto(value: ByteArray, destination: ByteArray) { + val input = pad(value) val h = initial.copyOf() + val w = LongArray(80) + val v = LongArray(8) - val blocks = pad(value) - .chunked(128) { it.toUByteArray() } - for (block in blocks) { - process(h, block) + for (i in input.indices step block) { + process(h, input, i, w, v) } - - return h.toUByteArray() + h.copyInto(destination) } - private fun pad( - value: UByteArray, - ): UByteArray { - val l = value.size.toULong() * 8UL - return buildList { - addAll(value) - add(0x80U) - while (size % 128 != 120) { - add(0x00U) - } - addAll(l.toUByteArray()) - }.toUByteArray() + internal fun pad(value: ByteArray): ByteArray { + val length = value.size.toULong() * 8UL + + val size = (value.size + 17).align(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: ULongArray, - block: UByteArray, - ) { - val w = buildList { - addAll(block.toULongArray()) - for (i in 16..79) { - val s0 = get(i - 15).rotateRight(1) xor get(i - 15).rotateRight(8) xor (get(i - 15) shr 7) - val s1 = get(i - 2).rotateRight(19) xor get(i - 2).rotateRight(61) xor (get(i - 2) shr 6) - add(get(i - 16) + s0 + get(i - 7) + s1) - } - }.toULongArray() - val v = h.copyOf() + internal fun process(h: LongArray, value: ByteArray, offset: Int, w: LongArray, v: LongArray) { + value.copyInto(w, startIndex = offset, endIndex = offset + block) + for (i in 16..<80) { + val s0 = w[i - 15].rotateRight(1) xor w[i - 15].rotateRight(8) xor (w[i - 15] ushr 7) + val s1 = w[i - 2].rotateRight(19) xor w[i - 2].rotateRight(61) xor (w[i - 2] ushr 6) + w[i] = (w[i - 16] + s0 + w[i - 7] + s1) + } + h.copyInto(v) repeat(80) { i -> val s0 = v[0].rotateRight(28) xor v[0].rotateRight(34) xor v[0].rotateRight(39) val s1 = v[4].rotateRight(14) xor v[4].rotateRight(18) xor v[4].rotateRight(41) val ch = (v[4] and v[5]) xor (v[4].inv() and v[6]) - val temp1 = v[7] + s1 + ch + this.c[i] + w[i] + val temp1 = v[7] + s1 + ch + c[i] + w[i] val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2]) val temp2 = s0 + maj @@ -101,7 +93,7 @@ object `SHA-512` : HashFunction { v[0] = temp1 + temp2 } - for (i in 0..7) { + for (i in 0..<8) { h[i] += v[i] } } diff --git a/src/commonMain/kotlin/com/infendro/hash/util/Math.kt b/src/commonMain/kotlin/com/infendro/hash/util/Math.kt new file mode 100644 index 0000000..d0ffcfc --- /dev/null +++ b/src/commonMain/kotlin/com/infendro/hash/util/Math.kt @@ -0,0 +1,6 @@ +package com.infendro.hash.util + +internal fun Int.align(n: Int): Int = when { + n and (n - 1) == 0 -> (this + n - 1) and (n - 1).inv() + else -> ((this + n - 1) / n) * n +} diff --git a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-224.kt b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-224.kt index cd50066..592bb7c 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-224.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-224.kt @@ -24,9 +24,9 @@ class `Blake-224 Test` { 0xecU, 0xbeU, 0xe0U, 0x90U, 0x3dU, 0x40U, 0xa8U, 0xa5U, 0x69U, 0xc9U, 0x4eU, 0xedU, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } @@ -41,9 +41,9 @@ class `Blake-224 Test` { 0xfeU, 0x3fU, 0x24U, 0x68U, 0xfeU, 0x31U, 0x2cU, 0x73U, 0xa5U, 0x27U, 0x8eU, 0xc5U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(1) + ByteArray(1), ) assertContentEquals(expected, actual) } @@ -58,9 +58,9 @@ class `Blake-224 Test` { 0x88U, 0x8dU, 0x82U, 0xc8U, 0xc0U, 0xa9U, 0x17U, 0x91U, 0x3cU, 0xfbU, 0x5dU, 0x04U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(72) + ByteArray(72), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-256.kt b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-256.kt index e77cd87..4f49609 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-256.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-256.kt @@ -25,9 +25,9 @@ class `Blake-256 Test` { 0x2fU, 0x67U, 0xc6U, 0x15U, 0x10U, 0xbfU, 0xc4U, 0x75U, 0x13U, 0x84U, 0xeaU, 0x7aU, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } @@ -43,9 +43,9 @@ class `Blake-256 Test` { 0x92U, 0x9aU, 0x74U, 0xdaU, 0x23U, 0x10U, 0x9eU, 0x8fU, 0x11U, 0x13U, 0x9cU, 0x87U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(1) + ByteArray(1), ) assertContentEquals(expected, actual) } @@ -61,9 +61,9 @@ class `Blake-256 Test` { 0x13U, 0x5dU, 0xecU, 0x31U, 0xe2U, 0x1bU, 0xd9U, 0xabU, 0xdcU, 0xc2U, 0x2dU, 0x41U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(72) + ByteArray(72), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-384.kt b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-384.kt index add61ae..e853f52 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-384.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-384.kt @@ -29,9 +29,9 @@ class `Blake-384 Test` { 0xddU, 0x2bU, 0x47U, 0x88U, 0xb1U, 0xc8U, 0x08U, 0x69U, 0x84U, 0xafU, 0x87U, 0x06U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } @@ -50,10 +50,10 @@ class `Blake-384 Test` { 0x29U, 0x39U, 0x1eU, 0x85U, 0x45U, 0xb5U, 0x27U, 0x2dU, 0x13U, 0xa7U, 0xc2U, 0x87U, - 0x9dU, 0xa3U, 0xd8U, 0x07U - ) + 0x9dU, 0xa3U, 0xd8U, 0x07U, + ).asByteArray() val actual = function.hash( - UByteArray(1) + ByteArray(1), ) assertContentEquals(expected, actual) } @@ -72,10 +72,10 @@ class `Blake-384 Test` { 0x69U, 0x78U, 0x0bU, 0x2dU, 0xaaU, 0x66U, 0xc4U, 0xb2U, 0x24U, 0xa2U, 0xecU, 0x2eU, - 0x5dU, 0x09U, 0x17U, 0x4cU - ) + 0x5dU, 0x09U, 0x17U, 0x4cU, + ).asByteArray() val actual = function.hash( - UByteArray(144) + ByteArray(144), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-512.kt b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-512.kt index a56d0d3..afa540f 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake/Blake-512.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake/Blake-512.kt @@ -33,9 +33,9 @@ class `Blake-512 Test` { 0xa2U, 0x5aU, 0x63U, 0x6dU, 0x80U, 0xafU, 0x3fU, 0xc7U, 0x91U, 0x3eU, 0xf5U, 0xb8U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } @@ -59,9 +59,9 @@ class `Blake-512 Test` { 0x8bU, 0xd0U, 0x81U, 0xb6U, 0x34U, 0x05U, 0x8bU, 0xe0U, 0xecU, 0x49U, 0xbeU, 0xb3U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(1) + ByteArray(1), ) assertContentEquals(expected, actual) } @@ -85,9 +85,9 @@ class `Blake-512 Test` { 0x6eU, 0x01U, 0xadU, 0x95U, 0x89U, 0xc2U, 0x13U, 0x04U, 0x5dU, 0x54U, 0x5dU, 0xdeU, - ) + ).asByteArray() val actual = function.hash( - UByteArray(144) + ByteArray(144), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-384.kt b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-384.kt index e463156..62defc3 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-384.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-384.kt @@ -29,9 +29,9 @@ class `Blake2b-384 Test` { 0x98U, 0x81U, 0x26U, 0x73U, 0xc5U, 0xe0U, 0x5eU, 0xf5U, 0x83U, 0x82U, 0x51U, 0x00U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-512.kt b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-512.kt index ee4d83a..de82fc4 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-512.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2b-512.kt @@ -33,9 +33,9 @@ class `Blake2b-512 Test` { 0x14U, 0x48U, 0xb7U, 0x55U, 0xd5U, 0x6fU, 0x70U, 0x1aU, 0xfeU, 0x9bU, 0xe2U, 0xceU, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-224.kt b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-224.kt index 7fde71b..5138eb1 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-224.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-224.kt @@ -24,9 +24,9 @@ class `Blake2s-224 Test` { 0xd5U, 0x4aU, 0x11U, 0xecU, 0xc4U, 0xe3U, 0xe0U, 0x34U, 0xe7U, 0xbcU, 0x1eU, 0xf4U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-256.kt b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-256.kt index 65e91db..06e48de 100644 --- a/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-256.kt +++ b/src/commonTest/kotlin/com/infendro/hash/blake2/Blake2s-256.kt @@ -25,9 +25,9 @@ class `Blake2s-256 Test` { 0x2cU, 0xa1U, 0xa5U, 0x1eU, 0x1bU, 0x25U, 0x0dU, 0xfdU, 0x1eU, 0xd0U, 0xeeU, 0xf9U, - ) + ).asByteArray() val actual = function.hash( - UByteArray(0) + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt index 19a5982..aa7845d 100644 --- a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt +++ b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-224.kt @@ -24,9 +24,9 @@ class `SHA3-224 Test` { 0xd4U, 0x59U, 0x7fU, 0x9aU, 0x1bU, 0x07U, 0x8eU, 0x3fU, 0x5bU, 0x5aU, 0x6bU, 0xc7U, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt index 815de1c..3f45c7d 100644 --- a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt +++ b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-256.kt @@ -25,9 +25,9 @@ class `SHA3-256 Test` { 0xe4U, 0x3bU, 0x49U, 0xfaU, 0x82U, 0xd8U, 0x0aU, 0x4bU, 0x80U, 0xf8U, 0x43U, 0x4aU, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt index 80ae376..b300062 100644 --- a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt +++ b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-384.kt @@ -29,9 +29,9 @@ class `SHA3-384 Test` { 0x26U, 0x4aU, 0xdbU, 0x47U, 0xfbU, 0x6bU, 0xd1U, 0xe0U, 0x58U, 0xd5U, 0xf0U, 0x04U, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt index 1e29b02..3cdacf7 100644 --- a/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt +++ b/src/commonTest/kotlin/com/infendro/hash/keccak/sha3/SHA3-512.kt @@ -33,9 +33,9 @@ class `SHA3-512 Test` { 0x95U, 0xb6U, 0xd3U, 0xe3U, 0x01U, 0x75U, 0x85U, 0x86U, 0x28U, 0x1dU, 0xcdU, 0x26U, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt b/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt index 9d29cbf..9a4cd1e 100644 --- a/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt +++ b/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE128.kt @@ -25,9 +25,9 @@ class `SHAKE128 Test` { 0xf6U, 0xefU, 0xbcU, 0x88U, 0xebU, 0x1aU, 0x6eU, 0xacU, 0xfaU, 0x66U, 0xefU, 0x26U, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt b/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt index 8086dfe..2543878 100644 --- a/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt +++ b/src/commonTest/kotlin/com/infendro/hash/keccak/shake/SHAKE256.kt @@ -33,9 +33,9 @@ class `SHAKE256 Test` { 0x47U, 0x9aU, 0xb4U, 0x86U, 0x40U, 0x29U, 0x2eU, 0xacU, 0xb3U, 0xb7U, 0xc4U, 0xbeU, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/md/MD5.kt b/src/commonTest/kotlin/com/infendro/hash/md/MD5.kt index 7d95d69..9b542cd 100644 --- a/src/commonTest/kotlin/com/infendro/hash/md/MD5.kt +++ b/src/commonTest/kotlin/com/infendro/hash/md/MD5.kt @@ -21,9 +21,9 @@ class `MD5 Test` { 0x8fU, 0x00U, 0xb2U, 0x04U, 0xe9U, 0x80U, 0x09U, 0x98U, 0xecU, 0xf8U, 0x42U, 0x7eU, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/sha1/SHA1.kt b/src/commonTest/kotlin/com/infendro/hash/sha1/SHA1.kt index 1b8101f..32018df 100644 --- a/src/commonTest/kotlin/com/infendro/hash/sha1/SHA1.kt +++ b/src/commonTest/kotlin/com/infendro/hash/sha1/SHA1.kt @@ -22,9 +22,9 @@ class `SHA1 Test` { 0x32U, 0x55U, 0xbfU, 0xefU, 0x95U, 0x60U, 0x18U, 0x90U, 0xafU, 0xd8U, 0x07U, 0x09U, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-224.kt b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-224.kt index f97d449..e324370 100644 --- a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-224.kt +++ b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-224.kt @@ -24,9 +24,9 @@ class `SHA-224 Test` { 0x15U, 0xa2U, 0xb0U, 0x1fU, 0x82U, 0x8eU, 0xa6U, 0x2aU, 0xc5U, 0xb3U, 0xe4U, 0x2fU, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-256.kt b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-256.kt index 5bf43c5..4cba687 100644 --- a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-256.kt +++ b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-256.kt @@ -25,9 +25,9 @@ class `SHA-256 Test` { 0x64U, 0x9bU, 0x93U, 0x4cU, 0xa4U, 0x95U, 0x99U, 0x1bU, 0x78U, 0x52U, 0xb8U, 0x55U, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-384.kt b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-384.kt index eb09dc3..68a0704 100644 --- a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-384.kt +++ b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-384.kt @@ -29,9 +29,9 @@ class `SHA-384 Test` { 0xe7U, 0x6fU, 0x65U, 0xfbU, 0xd5U, 0x1aU, 0xd2U, 0xf1U, 0x48U, 0x98U, 0xb9U, 0x5bU, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) } diff --git a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-512.kt b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-512.kt index fd4bbe2..1ac9cc6 100644 --- a/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-512.kt +++ b/src/commonTest/kotlin/com/infendro/hash/sha2/SHA-512.kt @@ -33,9 +33,9 @@ class `SHA-512 Test` { 0x47U, 0x41U, 0x7aU, 0x81U, 0xa5U, 0x38U, 0x32U, 0x7aU, 0xf9U, 0x27U, 0xdaU, 0x3eU, - ) + ).asByteArray() val actual = function.hash( - ubyteArrayOf() + ByteArray(0), ) assertContentEquals(expected, actual) }