implement optimizations

This commit is contained in:
2026-01-15 22:06:28 +01:00
parent ab036f4f9f
commit d40df04e2e
26 changed files with 463 additions and 855 deletions

View File

@@ -1,54 +1,9 @@
on: on:
push: push:
branches: [ develop, main ]
pull_request:
branches: [ main ] branches: [ main ]
jobs: 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: 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: Test
run: ./gradlew allTests
publish: publish:
needs: test
if: ${{ github.ref_name == 'main' }}
runs-on: linux runs-on: linux
steps: steps:
- name: Checkout - name: Checkout

View File

@@ -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

View File

@@ -11,15 +11,6 @@ Supported algorithms:
- Blake (Blake-224, Blake-256, Blake-384, Blake-512) - Blake (Blake-224, Blake-256, Blake-384, Blake-512)
- Blake2 (Blake2s, Blake2b) - Blake2 (Blake2s, Blake2b)
## Targets
| Target | Status |
|------------------|---------------|
| JVM | Supported |
| JavaScript | Supported |
| Native (Linux) | Supported |
| Native (Windows) | Not Supported |
## Installation ## Installation
Add the following to your `build.gradle.kts`. Add the following to your `build.gradle.kts`.
@@ -30,19 +21,16 @@ repositories {
} }
dependencies { dependencies {
implementation("com.infendro:hash:1.3.2") implementation("com.infendro:hash:1.5.0")
} }
``` ```
## Usage ## Usage
```kotlin ```kotlin
import com.infendro.hash.sha2.`SHA-256`
fun main() { fun main() {
// hash some value using SHA-256 // hash some value using SHA-256
val value = "Hello World!" val value = "Hello World!".encodeToByteArray()
.encodeToByteArray().asUByteArray()
val hash = `SHA-256`.hash(value) val hash = `SHA-256`.hash(value)
} }
``` ```

View File

@@ -1,8 +1,11 @@
@file:OptIn(ExperimentalWasmDsl::class)
import com.infendro.plugin.infendro import com.infendro.plugin.infendro
import com.infendro.plugin.token import com.infendro.plugin.token
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
group = "com.infendro" group = "com.infendro"
version = "1.4.0" version = "1.5.0"
plugins { plugins {
alias(libs.plugins.infendro) alias(libs.plugins.infendro)
@@ -13,9 +16,13 @@ plugins {
kotlin { kotlin {
jvm() jvm()
linuxX64() linuxX64()
js { linuxArm64()
nodejs() mingwX64()
} macosX64()
macosArm64()
js { nodejs() }
wasmJs { nodejs() }
wasmWasi { nodejs() }
repositories { repositories {
infendro() infendro()
@@ -24,7 +31,7 @@ kotlin {
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {
implementation(libs.bytearray) implementation(libs.bytes)
} }
commonTest.dependencies { commonTest.dependencies {
implementation(libs.test) implementation(libs.test)

View File

@@ -1,12 +1,12 @@
[versions] [versions]
infendro = "1.0.0" infendro = "1.1.0"
kotlin = "2.2.21" kotlin = "2.3.0"
bytearray = "1.2.4" bytes = "1.3.2"
[plugins] [plugins]
infendro = { id = "com.infendro.plugin", version.ref = "infendro" } infendro = { id = "com.infendro.plugin", version.ref = "infendro" }
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
[libraries] [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" } test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }

View File

@@ -7,7 +7,20 @@ interface HashFunction {
val block: Int val block: Int
fun hash( fun hashInto(value: ByteArray, destination: ByteArray)
value: UByteArray,
): UByteArray 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) }
} }

View File

@@ -1,8 +1,9 @@
package com.infendro.hash.blake package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.intarray.copyInto
import com.infendro.bytearray.toUIntArray import com.infendro.bytes.ulong.copyInto
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
import com.infendro.hash.util.ceilPow2
object `Blake-224` : HashFunction { object `Blake-224` : HashFunction {
override val bytes: Int override val bytes: Int
@@ -16,108 +17,31 @@ object `Blake-224` : HashFunction {
0x3070dd17U, 0xf70e5939U, 0x3070dd17U, 0xf70e5939U,
0xffc00b31U, 0x68581511U, 0xffc00b31U, 0x68581511U,
0x64f98fa7U, 0xbefa4fa4U, 0x64f98fa7U, 0xbefa4fa4U,
) ).asIntArray()
private val c = uintArrayOf( override fun hashInto(value: ByteArray, destination: ByteArray) {
0x243f6a88U, 0x85a308d3U, val length = value.size.toULong() * 8UL
0x13198a2eU, 0x03707344U, val input = pad(value)
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
val h = initial.copyOf() val h = initial.copyOf()
val m = IntArray(16)
val v = IntArray(16)
var t = 0U var t = 0U
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } t += minOf(length - t, 512UL).toUInt()
for (block in blocks) { `Blake-256`.compress(h, input, i, m, v, t)
t += minOf(l - t, 512UL).toUInt() }
compress(h, block, t) h.copyInto(destination, endIndex = 7)
} }
return h.sliceArray(0..6).toUByteArray() private fun pad(value: ByteArray): ByteArray {
} val length = value.size.toULong() * 8UL
private fun pad( val size = ceilPow2(value.size + 9, block)
value: UByteArray, val result = ByteArray(size)
): UByteArray { value.copyInto(result)
val l = value.size.toULong() * 8UL result[value.size] = 0x80U.toByte()
return buildList { length.copyInto(result, result.size - 8)
addAll(value) return result
add(0x80U)
while (size % 64 != 56) {
add(0x00U)
}
addAll(l.toUByteArray())
}.toUByteArray()
}
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)
} }
} }

View File

@@ -1,8 +1,10 @@
package com.infendro.hash.blake package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
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.HashFunction
import com.infendro.hash.util.ceilPow2
object `Blake-256` : HashFunction { object `Blake-256` : HashFunction {
override val bytes: Int override val bytes: Int
@@ -16,7 +18,7 @@ object `Blake-256` : HashFunction {
0x3c6ef372U, 0xa54ff53aU, 0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU, 0x510e527fU, 0x9b05688cU,
0x1f83d9abU, 0x5be0cd19U, 0x1f83d9abU, 0x5be0cd19U,
) ).asIntArray()
private val c = uintArrayOf( private val c = uintArrayOf(
0x243f6a88U, 0x85a308d3U, 0x243f6a88U, 0x85a308d3U,
@@ -27,7 +29,7 @@ object `Blake-256` : HashFunction {
0xbe5466cfU, 0x34e90c6cU, 0xbe5466cfU, 0x34e90c6cU,
0xc0ac29b7U, 0xc97c50ddU, 0xc0ac29b7U, 0xc97c50ddU,
0x3f84d5b5U, 0xb5470917U, 0x3f84d5b5U, 0xb5470917U,
) ).asIntArray()
private val sigma = arrayOf( private val sigma = arrayOf(
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 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), intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0),
) )
override fun hash(value: UByteArray): UByteArray { override fun hashInto(value: ByteArray, destination: ByteArray) {
val l = value.size.toULong() * 8UL val length = value.size.toULong() * 8UL
val input = pad(value)
val h = initial.copyOf() val h = initial.copyOf()
val m = IntArray(16)
val v = IntArray(16)
var t = 0U var t = 0U
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } t += minOf(length - t, 512UL).toUInt()
for (block in blocks) { compress(h, input, i, m, v, t)
t += minOf(l - t, 512UL).toUInt() }
compress(h, block, t) h.copyInto(destination)
} }
return h.toUByteArray() private fun pad(value: ByteArray): ByteArray {
val length = value.size.toULong() * 8UL
val size = ceilPow2(value.size + 10, 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 pad( internal fun compress(h: IntArray, value: ByteArray, offset: Int, m: IntArray, v: IntArray, t: UInt) {
value: UByteArray, value.copyInto(m, startIndex = offset, endIndex = offset + block)
): 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 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..<8) v[i] = h[i]
for (i in 0..<4) v[i + 8] = c[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] for (i in 0..<2) v[i + 14] = c[i + 6]
repeat(14) { r -> 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]]) 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] h[i] = h[i] xor v[i] xor v[i + 8]
} }
} }
private fun g( private fun g(v: IntArray, a: Int, b: Int, c: Int, d: Int, x: Int, y: Int) {
v: UIntArray,
a: Int,
b: Int,
c: Int,
d: Int,
x: UInt,
y: UInt,
) {
v[a] += v[b] + x v[a] += v[b] + x
v[d] = (v[d] xor v[a]).rotateRight(16) v[d] = (v[d] xor v[a]).rotateRight(16)
v[c] += v[d] v[c] += v[d]

View File

@@ -1,8 +1,9 @@
package com.infendro.hash.blake package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.longarray.copyInto
import com.infendro.bytearray.toULongArray import com.infendro.bytes.ulong.copyInto
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
import com.infendro.hash.util.ceilPow2
object `Blake-384` : HashFunction { object `Blake-384` : HashFunction {
override val bytes: Int override val bytes: Int
@@ -16,108 +17,31 @@ object `Blake-384` : HashFunction {
0x9159015a3070dd17U, 0x152fecd8f70e5939U, 0x9159015a3070dd17U, 0x152fecd8f70e5939U,
0x67332667ffc00b31U, 0x8eb44a8768581511U, 0x67332667ffc00b31U, 0x8eb44a8768581511U,
0xdb0c2e0d64f98fa7U, 0x47b5481dbefa4fa4U, 0xdb0c2e0d64f98fa7U, 0x47b5481dbefa4fa4U,
) ).asLongArray()
private val c = ulongArrayOf( override fun hashInto(value: ByteArray, destination: ByteArray) {
0x243f6a8885a308d3UL, 0x13198a2e03707344UL, val length = value.size.toULong() * 8UL
0xa4093822299f31d0UL, 0x082efa98ec4e6c89UL, val input = pad(value)
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
val h = initial.copyOf() val h = initial.copyOf()
val m = LongArray(16)
val v = LongArray(16)
var t = 0UL var t = 0UL
val blocks = pad(value) for (i in input.indices step block) {
.chunked(128) { it.toUByteArray() } t += minOf(length - t, 1024UL)
for (block in blocks) { `Blake-512`.compress(h, input, i, m, v, t)
t += minOf(l - t, 1024UL) }
compress(h, block, t) h.copyInto(destination, endIndex = 6)
} }
return h.sliceArray(0..5).toUByteArray() private fun pad(value: ByteArray): ByteArray {
} val length = value.size.toULong() * 8UL
private fun pad( val size = ceilPow2(value.size + 17, block)
value: UByteArray, val result = ByteArray(size)
): UByteArray { value.copyInto(result)
val l = value.size.toULong() * 8UL result[value.size] = 0x80U.toByte()
return buildList { length.copyInto(result, result.size - 8)
addAll(value) return result
add(0x80U)
while (size % 128 != 120) {
add(0x00U)
}
addAll(l.toUByteArray())
}.toUByteArray()
}
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)
} }
} }

View File

@@ -1,8 +1,10 @@
package com.infendro.hash.blake package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
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.HashFunction
import com.infendro.hash.util.ceilPow2
object `Blake-512` : HashFunction { object `Blake-512` : HashFunction {
override val bytes: Int override val bytes: Int
@@ -16,7 +18,7 @@ object `Blake-512` : HashFunction {
0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL,
0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL,
) ).asLongArray()
private val c = ulongArrayOf( private val c = ulongArrayOf(
0x243f6a8885a308d3UL, 0x13198a2e03707344UL, 0x243f6a8885a308d3UL, 0x13198a2e03707344UL,
@@ -27,7 +29,7 @@ object `Blake-512` : HashFunction {
0x2ffd72dbd01adfb7UL, 0xb8e1afed6a267e96UL, 0x2ffd72dbd01adfb7UL, 0xb8e1afed6a267e96UL,
0xba7c9045f12c7f99UL, 0x24a19947b3916cf7UL, 0xba7c9045f12c7f99UL, 0x24a19947b3916cf7UL,
0x0801f2e2858efc16UL, 0x636920d871574e69UL, 0x0801f2e2858efc16UL, 0x636920d871574e69UL,
) ).asLongArray()
private val sigma = arrayOf( private val sigma = arrayOf(
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 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), intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0),
) )
override fun hash(value: UByteArray): UByteArray { override fun hashInto(value: ByteArray, destination: ByteArray) {
val l = value.size.toULong() * 8UL val length = value.size.toULong() * 8UL
val input = pad(value)
val h = initial.copyOf() val h = initial.copyOf()
val m = LongArray(16)
val v = LongArray(16)
var t = 0UL var t = 0UL
val blocks = pad(value) for (i in input.indices step block) {
.chunked(128) { it.toUByteArray() } t += minOf(length - t, 1024UL)
for (block in blocks) { compress(h, input, i, m, v, t)
t += minOf(l - t, 1024UL) }
compress(h, block, t) h.copyInto(destination)
} }
return h.toUByteArray() private fun pad(value: ByteArray): ByteArray {
val length = value.size.toULong() * 8UL
val size = ceilPow2(value.size + 18, 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 pad( internal fun compress(h: LongArray, value: ByteArray, offset: Int, m: LongArray, v: LongArray, t: ULong) {
value: UByteArray, value.copyInto(m, startIndex = offset, endIndex = offset + block)
): 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 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..<8) v[i] = h[i]
for (i in 0..<4) v[i + 8] = c[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] for (i in 0..<2) v[i + 14] = c[i + 6]
repeat(16) { r -> 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]]) 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] h[i] = h[i] xor v[i] xor v[i + 8]
} }
} }
private fun g( private fun g(v: LongArray, a: Int, b: Int, c: Int, d: Int, x: Long, y: Long) {
v: ULongArray,
a: Int,
b: Int,
c: Int,
d: Int,
x: ULong,
y: ULong,
) {
v[a] += v[b] + x v[a] += v[b] + x
v[d] = (v[d] xor v[a]).rotateRight(32) v[d] = (v[d] xor v[a]).rotateRight(32)
v[c] += v[d] v[c] += v[d]

View File

@@ -1,9 +1,10 @@
package com.infendro.hash.blake2 package com.infendro.hash.blake2
import com.infendro.bytearray.ByteOrder import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
import com.infendro.bytearray.toULongArray import com.infendro.bytes.longarray.toByteArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
import com.infendro.hash.util.ceilPow2
class Blake2b( class Blake2b(
override val bytes: Int, override val bytes: Int,
@@ -20,7 +21,7 @@ class Blake2b(
0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL,
0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL,
) ).asLongArray()
private val sigma = arrayOf( private val sigma = arrayOf(
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 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), intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0),
) )
override fun hash(value: UByteArray): UByteArray { override fun hashInto(value: ByteArray, destination: ByteArray) {
val l = value.size.toULong() val length = value.size.toULong()
val input = pad(value)
val h = initial.copyOf() 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 var t = 0UL
val blocks = pad(value) for (i in input.indices step block) {
.chunked(128) { it.toUByteArray() } t += minOf(length - t, 128UL)
for ((i, block) in blocks.withIndex()) { compress(h, input, i, m, v, t, t < 1024UL)
t += minOf(l - t, 128UL) }
compress(h, block, t, i == blocks.lastIndex) h.toByteArray(LITTLE_ENDIAN).copyInto(destination, endIndex = bytes)
} }
return h.toUByteArray(ByteOrder.LITTLE_ENDIAN).sliceArray(0..<bytes) private fun pad(value: ByteArray): ByteArray {
} val size = maxOf(ceilPow2(value.size, block), block)
val result = ByteArray(size)
private fun pad( value.copyInto(result)
value: UByteArray, return result
): UByteArray {
return buildList {
addAll(value)
if (isEmpty()) add(0x00U)
while (size % 128 != 0) {
add(0x00U)
}
}.toUByteArray()
} }
private fun compress( private fun compress(
h: ULongArray, h: LongArray,
block: UByteArray, value: ByteArray,
offset: Int,
m: LongArray,
v: LongArray,
t: ULong, t: ULong,
last: Boolean, last: Boolean,
) { ) {
val m = block.toULongArray() value.copyInto(m, startIndex = offset, endIndex = offset + block)
val v = ULongArray(16)
for (i in 0..<8) v[i] = h[i] for (i in 0..<8) v[i] = h[i]
for (i in 0..<8) v[i + 8] = initial[i] for (i in 0..<8) v[i + 8] = initial[i]
v[12] = v[12] xor t v[12] = v[12] xor t.toLong()
if (last) v[14] = v[14].inv() if (last) v[14] = v[14].inv()
repeat(12) { r -> repeat(12) { r ->
@@ -90,20 +88,12 @@ class Blake2b(
mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) 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] h[i] = h[i] xor v[i] xor v[i + 8]
} }
} }
private fun mix( private fun mix(v: LongArray, a: Int, b: Int, c: Int, d: Int, x: Long, y: Long) {
v: ULongArray,
a: Int,
b: Int,
c: Int,
d: Int,
x: ULong,
y: ULong,
) {
v[a] += v[b] + x v[a] += v[b] + x
v[d] = (v[d] xor v[a]).rotateRight(32) v[d] = (v[d] xor v[a]).rotateRight(32)
v[c] += v[d] v[c] += v[d]

View File

@@ -1,9 +1,10 @@
package com.infendro.hash.blake2 package com.infendro.hash.blake2
import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
import com.infendro.bytearray.toUIntArray import com.infendro.bytes.intarray.toByteArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
import com.infendro.hash.util.ceilPow2
class Blake2s( class Blake2s(
override val bytes: Int, override val bytes: Int,
@@ -20,7 +21,7 @@ class Blake2s(
0x3c6ef372U, 0xa54ff53aU, 0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU, 0x510e527fU, 0x9b05688cU,
0x1f83d9abU, 0x5be0cd19U, 0x1f83d9abU, 0x5be0cd19U,
) ).asIntArray()
private val sigma = arrayOf( private val sigma = arrayOf(
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 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), intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0),
) )
override fun hash(value: UByteArray): UByteArray { override fun hashInto(value: ByteArray, destination: ByteArray) {
val l = value.size.toULong() val length = value.size.toULong()
val input = pad(value)
val h = initial.copyOf() 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 var t = 0U
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } t += minOf(length - t, 64UL).toUInt()
for ((i, block) in blocks.withIndex()) { compress(h, input, i, m, v, t, t < 1024UL)
t += minOf(l - t, 64UL).toUInt() }
compress(h, block, t, i == blocks.lastIndex) h.toByteArray(LITTLE_ENDIAN).copyInto(destination, endIndex = bytes)
} }
return h.toUByteArray(LITTLE_ENDIAN).sliceArray(0..<bytes) private fun pad(value: ByteArray): ByteArray {
} val size = maxOf(ceilPow2(value.size, block), block)
val result = ByteArray(size)
private fun pad( value.copyInto(result)
value: UByteArray, return result
): UByteArray {
return buildList {
addAll(value)
if (isEmpty()) add(0x00U)
while (size % 64 != 0) {
add(0x00U)
}
}.toUByteArray()
} }
private fun compress( private fun compress(
h: UIntArray, h: IntArray,
block: UByteArray, value: ByteArray,
offset: Int,
m: IntArray,
v: IntArray,
t: UInt, t: UInt,
last: Boolean, last: Boolean,
) { ) {
val m = block.toUIntArray() value.copyInto(m, startIndex = offset, endIndex = offset + block)
val v = UIntArray(16)
for (i in 0..<8) v[i] = h[i] for (i in 0..<8) v[i] = h[i]
for (i in 0..<8) v[i + 8] = initial[i] for (i in 0..<8) v[i + 8] = initial[i]
v[12] = v[12] xor t.toInt()
v[12] = v[12] xor t
if (last) v[14] = v[14].inv() if (last) v[14] = v[14].inv()
repeat(10) { r -> repeat(10) { r ->
@@ -91,20 +88,12 @@ class Blake2s(
mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) 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] h[i] = h[i] xor v[i] xor v[i + 8]
} }
} }
private fun mix( private fun mix(v: IntArray, a: Int, b: Int, c: Int, d: Int, x: Int, y: Int) {
v: UIntArray,
a: Int,
b: Int,
c: Int,
d: Int,
x: UInt,
y: UInt,
) {
v[a] += v[b] + x v[a] += v[b] + x
v[d] = (v[d] xor v[a]).rotateRight(16) v[d] = (v[d] xor v[a]).rotateRight(16)
v[c] += v[d] v[c] += v[d]

View File

@@ -1,15 +1,15 @@
package com.infendro.hash.keccak package com.infendro.hash.keccak
import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
import com.infendro.bytearray.toULongArray import com.infendro.bytes.long.copyInto
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
import kotlin.math.min import com.infendro.hash.util.ceil
abstract class Keccak( abstract class Keccak(
override val bytes: Int, override val bytes: Int,
private val rate: Int, private val rate: Int,
private val domain: UByte, private val domain: Byte,
) : HashFunction { ) : HashFunction {
override val block: Int override val block: Int
get() = rate get() = rate
@@ -21,7 +21,7 @@ abstract class Keccak(
0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL, 0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL,
0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL, 0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL,
0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL, 0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL,
) ).asLongArray()
private val rotation = arrayOf( private val rotation = arrayOf(
intArrayOf(0, 36, 3, 41, 18), intArrayOf(0, 36, 3, 41, 18),
@@ -31,52 +31,57 @@ abstract class Keccak(
intArrayOf(27, 20, 39, 8, 14), intArrayOf(27, 20, 39, 8, 14),
) )
override fun hash( override fun hashInto(value: ByteArray, destination: ByteArray) {
value: UByteArray, val input = pad(value)
): UByteArray { val state = LongArray(25)
val state = ULongArray(25) val w = LongArray(block / 8)
val b = LongArray(25)
val c = LongArray(5)
val d = LongArray(5)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(rate) { it.toUByteArray() } absorb(state, input, i, w)
for (block in blocks) { permute(state, b, c, d)
absorb(state, block) }
squeeze(state, b, c, d, destination)
} }
return squeeze(state) private fun pad(value: ByteArray): ByteArray {
val size = ceil(value.size + 2, block)
val result = ByteArray(size)
value.copyInto(result)
result[value.size] = domain
result[result.lastIndex] = 0x80U.toByte()
return result
} }
private fun pad( private fun absorb(state: LongArray, value: ByteArray, offset: Int, w: LongArray) {
value: UByteArray, value.copyInto(w, startIndex = offset, endIndex = offset + block, order = LITTLE_ENDIAN)
): UByteArray { for (i in w.indices) {
return buildList { state[i] = state[i] xor w[i]
addAll(value)
add(domain)
while ((size % rate) != (rate - 1)) {
add(0x00U)
} }
add(0x80U)
}.toUByteArray()
} }
private fun absorb( private fun squeeze(state: LongArray, b: LongArray, c: LongArray, d: LongArray, destination: ByteArray) {
state: ULongArray, val buffer = ByteArray(8)
block: UByteArray, var consumed = 0
) { var i = 0
val numbers = block.toULongArray(LITTLE_ENDIAN) while (consumed < bytes) {
for ((i, number) in numbers.withIndex()) { if (i == rate / 8) {
state[i] = state[i] xor number permute(state, b, c, d)
} i = 0
permute(state)
} }
private fun permute( val length = minOf(bytes - consumed, 8)
a: ULongArray, state[i].copyInto(buffer, order = LITTLE_ENDIAN)
) { buffer.copyInto(destination, consumed, endIndex = length)
val b = ULongArray(25)
val c = ULongArray(5)
val d = ULongArray(5)
repeat(24) { round -> consumed += length
i++
}
}
private fun permute(a: LongArray, b: LongArray, c: LongArray, d: LongArray) = repeat(24) { round ->
// θ // θ
for (x in 0..4) { 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] c[x] = a[x] xor a[x + 5] xor a[x + 10] xor a[x + 15] xor a[x + 20]
@@ -101,23 +106,4 @@ abstract class Keccak(
// ι // ι
a[0] = a[0] xor rc[round] a[0] = a[0] xor rc[round]
} }
}
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..<min(bytes - size, 8))
)
}
}.toUByteArray()
}
} }

View File

@@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-224` : Keccak(28, 144, 0x06U) object `SHA3-224` : Keccak(28, 144, 0x06)

View File

@@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-256` : Keccak(32, 136, 0x06U) object `SHA3-256` : Keccak(32, 136, 0x06)

View File

@@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-384` : Keccak(48, 104, 0x06U) object `SHA3-384` : Keccak(48, 104, 0x06)

View File

@@ -2,4 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-512` : Keccak(64, 72, 0x06U) object `SHA3-512` : Keccak(64, 72, 0x06)

View File

@@ -4,4 +4,4 @@ import com.infendro.hash.keccak.Keccak
class SHAKE128( class SHAKE128(
bytes: Int, bytes: Int,
) : Keccak(bytes, 168, 0x1FU) ) : Keccak(bytes, 168, 0x1F)

View File

@@ -4,4 +4,4 @@ import com.infendro.hash.keccak.Keccak
class SHAKE256( class SHAKE256(
bytes: Int, bytes: Int,
) : Keccak(bytes, 136, 0x1FU) ) : Keccak(bytes, 136, 0x1F)

View File

@@ -1,9 +1,11 @@
package com.infendro.hash.md package com.infendro.hash.md
import com.infendro.bytearray.ByteOrder.LITTLE_ENDIAN import com.infendro.bytes.ByteOrder.LITTLE_ENDIAN
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
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.HashFunction
import com.infendro.hash.util.ceilPow2
object MD5 : HashFunction { object MD5 : HashFunction {
override val bytes: Int override val bytes: Int
@@ -15,18 +17,7 @@ object MD5 : HashFunction {
private val initial = uintArrayOf( private val initial = uintArrayOf(
0x67452301U, 0xefcdab89U, 0x67452301U, 0xefcdab89U,
0x98badcfeU, 0x10325476U, 0x98badcfeU, 0x10325476U,
) ).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,
)
private val c = uintArrayOf( private val c = uintArrayOf(
0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU, 0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU,
@@ -45,54 +36,57 @@ object MD5 : HashFunction {
0x655b59c3U, 0x8f0ccc92U, 0xffeff47dU, 0x85845dd1U, 0x655b59c3U, 0x8f0ccc92U, 0xffeff47dU, 0x85845dd1U,
0x6fa87e4fU, 0xfe2ce6e0U, 0xa3014314U, 0x4e0811a1U, 0x6fa87e4fU, 0xfe2ce6e0U, 0xa3014314U, 0x4e0811a1U,
0xf7537e82U, 0xbd3af235U, 0x2ad7d2bbU, 0xeb86d391U, 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( override fun hashInto(value: ByteArray, destination: ByteArray) {
value: UByteArray, val input = pad(value)
): UByteArray {
val h = initial.copyOf() val h = initial.copyOf()
val w = IntArray(16)
val v = IntArray(4)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } process(h, input, i, w, v)
for (block in blocks) { }
process(h, block) h.copyInto(destination, order = LITTLE_ENDIAN)
} }
return h.toUByteArray(LITTLE_ENDIAN) 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, order = LITTLE_ENDIAN)
return result
} }
private fun pad( private fun process(h: IntArray, value: ByteArray, offset: Int, w: IntArray, v: IntArray) {
value: UByteArray, value.copyInto(w, startIndex = offset, endIndex = offset + block, order = LITTLE_ENDIAN)
): UByteArray { h.copyInto(v)
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 process(
h: UIntArray,
block: UByteArray,
) {
val w = block.toUIntArray(LITTLE_ENDIAN)
val v = h.copyOf()
repeat(64) { i -> repeat(64) { i ->
var f = when (i) { var f = when (i) {
in 0..15 -> (v[1] and v[2]) or (v[1].inv() and v[3]) in 0..<16 -> (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 16..<32 -> (v[3] and v[1]) or (v[3].inv() and v[2])
in 32..47 -> v[1] xor v[2] xor v[3] in 32..<48 -> v[1] xor v[2] xor v[3]
else -> v[2] xor (v[1] or v[3].inv()) else -> v[2] xor (v[1] or v[3].inv())
} }
val g = when (i) { val g = when (i) {
in 0..15 -> i in 0..<16 -> i
in 16..31 -> (5 * i + 1) % 16 in 16..<32 -> (5 * i + 1) % 16
in 32..47 -> (3 * i + 5) % 16 in 32..<48 -> (3 * i + 5) % 16
else -> (7 * i) % 16 else -> (7 * i) % 16
} }
f += v[0] + c[i] + w[g] f += v[0] + c[i] + w[g]
@@ -102,7 +96,7 @@ object MD5 : HashFunction {
v[1] += f.rotateLeft(shifts[i]) v[1] += f.rotateLeft(shifts[i])
} }
for (i in 0..3) { for (i in 0..<4) {
h[i] += v[i] h[i] += v[i]
} }
} }

View File

@@ -1,8 +1,10 @@
package com.infendro.hash.sha1 package com.infendro.hash.sha1
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
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.HashFunction
import com.infendro.hash.util.ceilPow2
object SHA1 : HashFunction { object SHA1 : HashFunction {
override val bytes: Int override val bytes: Int
@@ -15,48 +17,42 @@ object SHA1 : HashFunction {
0x67452301U, 0xefcdaB89U, 0x67452301U, 0xefcdaB89U,
0x98badcfeU, 0x10325476U, 0x98badcfeU, 0x10325476U,
0xc3d2e1f0U, 0xc3d2e1f0U,
) ).asIntArray()
override fun hash( private val k = uintArrayOf(
value: UByteArray, 0x5a827999U, 0x6ed9eba1U,
): UByteArray { 0x8f1bbcdcU, 0xca62c1d6U,
).asIntArray()
override fun hashInto(value: ByteArray, destination: ByteArray) {
val input = pad(value)
val h = initial.copyOf() val h = initial.copyOf()
val w = IntArray(80)
val v = IntArray(5)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } process(h, input, i, w, v)
for (block in blocks) { }
process(h, block) h.copyInto(destination)
} }
return h.toUByteArray() 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 pad( private fun process(h: IntArray, value: ByteArray, offset: Int, w: IntArray, v: IntArray) {
value: UByteArray, value.copyInto(w, startIndex = offset, endIndex = offset + block)
): UByteArray { for (i in 16..<80) {
val l = value.size.toULong() * 8UL w[i] = (w[i - 3] xor w[i - 8] xor w[i - 14] xor w[i - 16]).rotateLeft(1)
return buildList {
addAll(value)
add(0x80U)
while (size % 64 != 56) {
add(0x00U)
} }
addAll(l.toUByteArray()) h.copyInto(v)
}.toUByteArray()
}
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()
repeat(80) { i -> repeat(80) { i ->
val f = when (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]) 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] else -> v[1] xor v[2] xor v[3]
} }
val k = when (i) { val temp = v[0].rotateLeft(5) + f + v[4] + k[i / 20] + w[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]
v[4] = v[3] v[4] = v[3]
v[3] = v[2] v[3] = v[2]
v[2] = v[1].rotateLeft(30) v[2] = v[1].rotateLeft(30)
@@ -79,7 +69,7 @@ object SHA1 : HashFunction {
v[0] = temp v[0] = temp
} }
for (i in 0..4) { for (i in 0..<5) {
h[i] += v[i] h[i] += v[i]
} }
} }

View File

@@ -1,7 +1,6 @@
package com.infendro.hash.sha2 package com.infendro.hash.sha2
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.intarray.copyInto
import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object `SHA-224` : HashFunction { object `SHA-224` : HashFunction {
@@ -16,81 +15,17 @@ object `SHA-224` : HashFunction {
0x3070dd17U, 0xf70e5939U, 0x3070dd17U, 0xf70e5939U,
0xffc00b31U, 0x68581511U, 0xffc00b31U, 0x68581511U,
0x64f98fa7U, 0xbefa4fa4U, 0x64f98fa7U, 0xbefa4fa4U,
) ).asIntArray()
private val c = uintArrayOf( override fun hashInto(value: ByteArray, destination: ByteArray) {
0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, val input = `SHA-256`.pad(value)
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 {
val h = initial.copyOf() val h = initial.copyOf()
val w = IntArray(64)
val v = IntArray(8)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } `SHA-256`.process(h, input, i, w, v)
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]
} }
h.copyInto(destination, endIndex = 7)
} }
} }

View File

@@ -1,8 +1,10 @@
package com.infendro.hash.sha2 package com.infendro.hash.sha2
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
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.HashFunction
import com.infendro.hash.util.ceilPow2
object `SHA-256` : HashFunction { object `SHA-256` : HashFunction {
override val bytes: Int override val bytes: Int
@@ -16,7 +18,7 @@ object `SHA-256` : HashFunction {
0x3c6ef372U, 0xa54ff53aU, 0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU, 0x510e527fU, 0x9b05688cU,
0x1f83d9abU, 0x5be0cd19U, 0x1f83d9abU, 0x5be0cd19U,
) ).asIntArray()
private val c = uintArrayOf( private val c = uintArrayOf(
0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
@@ -27,49 +29,39 @@ object `SHA-256` : HashFunction {
0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U, 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U,
0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U, 0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U,
0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U,
) ).asIntArray()
override fun hash( override fun hashInto(value: ByteArray, destination: ByteArray) {
value: UByteArray, val input = pad(value)
): UByteArray {
val h = initial.copyOf() val h = initial.copyOf()
val w = IntArray(64)
val v = IntArray(8)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(64) { it.toUByteArray() } process(h, input, i, w, v)
for (block in blocks) { }
process(h, block) h.copyInto(destination)
} }
return h.toUByteArray() internal 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 pad( internal fun process(h: IntArray, value: ByteArray, offset: Int, w: IntArray, v: IntArray) {
value: UByteArray, value.copyInto(w, startIndex = offset, endIndex = offset + block)
): UByteArray { for (i in 16..<64) {
val l = value.size.toULong() * 8UL val s0 = w[i - 15].rotateRight(7) xor w[i - 15].rotateRight(18) xor (w[i - 15] ushr 3)
return buildList { val s1 = w[i - 2].rotateRight(17) xor w[i - 2].rotateRight(19) xor (w[i - 2] ushr 10)
addAll(value) w[i] = (w[i - 16] + s0 + w[i - 7] + s1)
add(0x80U)
while (size % 64 != 56) {
add(0x00U)
} }
addAll(l.toUByteArray()) h.copyInto(v)
}.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 -> repeat(64) { i ->
val s0 = v[0].rotateRight(2) xor v[0].rotateRight(13) xor v[0].rotateRight(22) 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 v[0] = temp1 + temp2
} }
for (i in 0..7) { for (i in 0..<8) {
h[i] += v[i] h[i] += v[i]
} }
} }

View File

@@ -1,7 +1,6 @@
package com.infendro.hash.sha2 package com.infendro.hash.sha2
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.longarray.copyInto
import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object `SHA-384` : HashFunction { object `SHA-384` : HashFunction {
@@ -16,93 +15,17 @@ object `SHA-384` : HashFunction {
0x9159015a3070dd17UL, 0x152fecd8f70e5939UL, 0x9159015a3070dd17UL, 0x152fecd8f70e5939UL,
0x67332667ffc00b31UL, 0x8eb44a8768581511UL, 0x67332667ffc00b31UL, 0x8eb44a8768581511UL,
0xdb0c2e0d64f98fa7UL, 0x47b5481dbefa4fa4UL, 0xdb0c2e0d64f98fa7UL, 0x47b5481dbefa4fa4UL,
) ).asLongArray()
private val c = ulongArrayOf( override fun hashInto(value: ByteArray, destination: ByteArray) {
0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, val input = `SHA-512`.pad(value)
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 {
val h = initial.copyOf() val h = initial.copyOf()
val w = LongArray(80)
val v = LongArray(8)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(128) { it.toUByteArray() } `SHA-512`.process(h, input, i, w, v)
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]
} }
h.copyInto(destination, endIndex = 6)
} }
} }

View File

@@ -1,8 +1,10 @@
package com.infendro.hash.sha2 package com.infendro.hash.sha2
import com.infendro.bytearray.toUByteArray import com.infendro.bytes.bytearray.copyInto
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.HashFunction
import com.infendro.hash.util.ceilPow2
object `SHA-512` : HashFunction { object `SHA-512` : HashFunction {
override val bytes: Int override val bytes: Int
@@ -16,7 +18,7 @@ object `SHA-512` : HashFunction {
0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL,
0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL,
) ).asLongArray()
private val c = ulongArrayOf( private val c = ulongArrayOf(
0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
@@ -39,55 +41,45 @@ object `SHA-512` : HashFunction {
0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, 0x1b710b35131c471bUL, 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, 0x1b710b35131c471bUL,
0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL, 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL,
0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL, 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL,
) ).asLongArray()
override fun hash( override fun hashInto(value: ByteArray, destination: ByteArray) {
value: UByteArray, val input = pad(value)
): UByteArray {
val h = initial.copyOf() val h = initial.copyOf()
val w = LongArray(80)
val v = LongArray(8)
val blocks = pad(value) for (i in input.indices step block) {
.chunked(128) { it.toUByteArray() } process(h, input, i, w, v)
for (block in blocks) { }
process(h, block) h.copyInto(destination)
} }
return h.toUByteArray() internal fun pad(value: ByteArray): ByteArray {
val length = value.size.toULong() * 8UL
val size = ceilPow2(value.size + 17, block)
val result = ByteArray(size)
value.copyInto(result)
result[value.size] = 0x80U.toByte()
length.copyInto(result, result.size - 8)
return result
} }
private fun pad( internal fun process(h: LongArray, value: ByteArray, offset: Int, w: LongArray, v: LongArray) {
value: UByteArray, value.copyInto(w, startIndex = offset, endIndex = offset + block)
): UByteArray { for (i in 16..<80) {
val l = value.size.toULong() * 8UL val s0 = w[i - 15].rotateRight(1) xor w[i - 15].rotateRight(8) xor (w[i - 15] ushr 7)
return buildList { val s1 = w[i - 2].rotateRight(19) xor w[i - 2].rotateRight(61) xor (w[i - 2] ushr 6)
addAll(value) w[i] = (w[i - 16] + s0 + w[i - 7] + s1)
add(0x80U)
while (size % 128 != 120) {
add(0x00U)
} }
addAll(l.toUByteArray()) h.copyInto(v)
}.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 -> repeat(80) { i ->
val s0 = v[0].rotateRight(28) xor v[0].rotateRight(34) xor v[0].rotateRight(39) 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 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 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 maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2])
val temp2 = s0 + maj val temp2 = s0 + maj
@@ -101,7 +93,7 @@ object `SHA-512` : HashFunction {
v[0] = temp1 + temp2 v[0] = temp1 + temp2
} }
for (i in 0..7) { for (i in 0..<8) {
h[i] += v[i] h[i] += v[i]
} }
} }

View File

@@ -0,0 +1,7 @@
package com.infendro.hash.util
internal fun ceil(x: Int, n: Int): Int =
((x + n - 1) / n) * n
internal fun ceilPow2(x: Int, n: Int): Int =
(x + n - 1) and (n - 1).inv()