Compare commits

..

18 Commits

Author SHA1 Message Date
f3af9d3361 bump version to 1.4.0
All checks were successful
/ publish (push) Successful in 3m51s
2025-12-14 14:11:49 +01:00
87c606d6dd replace IllegalArgumentException with require 2025-12-14 00:13:41 +01:00
197beb828a upgrade dependency 2025-12-13 21:00:33 +01:00
ab57683797 update README 2025-12-13 21:00:22 +01:00
b0bb2e66a8 fix workflow 2025-12-13 01:29:31 +01:00
ebdf640934 small refactor 2025-12-13 01:09:19 +01:00
6c74c64dec refactor build.gradle.kts 2025-12-13 00:59:33 +01:00
a2731bd60c use common plugin 2025-12-13 00:56:02 +01:00
1ddda4889a convert HashFunction to interface 2025-12-12 14:08:52 +01:00
17b765b13c refactor SHA1 and SHA2 2025-12-04 19:20:35 +01:00
b41debf948 refactor MD5 2025-12-04 19:13:43 +01:00
6dc3cf3b87 refactor Keccak 2025-12-04 19:13:39 +01:00
16390b0308 refactor Blake and Blake2 2025-12-04 19:05:54 +01:00
85ab748c07 implement Blake2b and Blake2s 2025-12-02 19:34:26 +01:00
3ff0ad1b91 refactor keccak functions 2025-12-02 19:13:52 +01:00
324d907d0c implement blake 2025-12-01 19:40:20 +01:00
8a2848e6e3 refactor hash functions 2025-12-01 19:13:58 +01:00
10ba03dedc upgrade kotlin version and dependencies 2025-12-01 19:13:26 +01:00
33 changed files with 1696 additions and 554 deletions

View File

@@ -4,7 +4,7 @@ on:
- main - main
env: env:
GIT__TOKEN: ${{ secrets.TOKEN }} INFENDRO__TOKEN: ${{ secrets.TOKEN }}
jobs: jobs:
publish: publish:

View File

@@ -1,20 +1,24 @@
# Kotlin Hash # hash-kt
This library provides various [Cryptographic Hash Function](https://en.wikipedia.org/wiki/Cryptographic_hash_function) `hash-kt` is a Kotlin Multiplatform library that provides common cryptographic hash functions.
implementations in Kotlin Multiplatform.
## Features Supported hash functions:
- MD5
- SHA-1
- SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512)
- SHA-3 (SHA3-224, SHA3-256, SHA3-384, SHA3-512)
- SHAKE (SHAKE128, SHAKE256)
- Blake (Blake-224, Blake-256, Blake-384, Blake-512)
- Blake2 (Blake2s, Blake2b)
* [MD5](https://en.wikipedia.org/wiki/MD5) ## Targets
* [SHA1](https://en.wikipedia.org/wiki/SHA-1)
* [SHA224](https://en.wikipedia.org/wiki/SHA-2) | Target | Status |
* [SHA256](https://en.wikipedia.org/wiki/SHA-2) |------------------|---------------|
* [SHA384](https://en.wikipedia.org/wiki/SHA-2) | JVM | Supported |
* [SHA512](https://en.wikipedia.org/wiki/SHA-2) | JavaScript | Supported |
* Multiplatform support | Native (Linux) | Supported |
* JVM | Native (Windows) | Not Supported |
* JavaScript
* Native (Linux)
## Installation ## Installation
@@ -26,18 +30,19 @@ repositories {
} }
dependencies { dependencies {
implementation("com.infendro:hash:1.2.2") implementation("com.infendro:hash:1.3.2")
} }
``` ```
## Usage ## Usage
```kotlin ```kotlin
import com.infendro.hash.SHA256 import com.infendro.hash.sha2.`SHA-256`
fun main() { fun main() {
// hash some value using SHA256 // hash some value using SHA-256
val value = "...".encodeToByteArray() val value = "Hello World!"
val hash = SHA256.hash(value) .encodeToByteArray().asUByteArray()
val hash = `SHA-256`.hash(value)
} }
``` ```

View File

@@ -1,12 +1,11 @@
group = "com.infendro" import com.infendro.plugin.infendro
version = "1.3.2" import com.infendro.plugin.token
repositories { group = "com.infendro"
maven("https://git.infendro.com/api/packages/Infendro/maven") version = "1.4.0"
mavenCentral()
}
plugins { plugins {
alias(libs.plugins.infendro)
alias(libs.plugins.multiplatform) alias(libs.plugins.multiplatform)
id("maven-publish") id("maven-publish")
} }
@@ -18,6 +17,11 @@ kotlin {
} }
linuxX64() linuxX64()
repositories {
infendro()
mavenCentral()
}
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {
implementation(libs.bytearray) implementation(libs.bytearray)
@@ -32,31 +36,6 @@ kotlin {
} }
} }
publishing { publishing.repositories {
repositories { infendro(token)
maven {
url = uri("https://git.infendro.com/api/packages/Infendro/maven")
authentication.create("header", HttpHeaderAuthentication::class)
credentials(HttpHeaderCredentials::class) {
val token = secret("git.token") ?: throw GradleException()
name = "Authorization"
value = "token $token"
}
}
}
}
fun secret(
key: String,
): String? {
val property = key
val environment = key
.uppercase()
.replace(".", "__")
val prop = properties[property] as String?
val env = System.getenv(environment)
return prop ?: env
} }

View File

@@ -1,8 +1,10 @@
[versions] [versions]
kotlin = "2.1.20" infendro = "1.0.0"
bytearray = "1.2.2" kotlin = "2.2.21"
bytearray = "1.2.4"
[plugins] [plugins]
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]

View File

@@ -1 +1,6 @@
rootProject.name = "hash" rootProject.name = "hash"
pluginManagement.repositories {
maven("https://git.infendro.com/api/packages/Infendro/maven")
mavenCentral()
}

View File

@@ -1,13 +1,13 @@
package com.infendro.hash package com.infendro.hash
abstract class HashFunction { interface HashFunction {
abstract val bytes: Int val bytes: Int
val bits: Int val bits: Int
get() = bytes * 8 get() = bytes * 8
abstract val block: Int val block: Int
abstract fun hash( fun hash(
value: UByteArray, value: UByteArray,
): UByteArray ): UByteArray
} }

View File

@@ -0,0 +1,123 @@
package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction
object `Blake-224` : HashFunction {
override val bytes: Int
get() = 28
override val block: Int
get() = 64
private val initial = uintArrayOf(
0xc1059ed8U, 0x367cd507U,
0x3070dd17U, 0xf70e5939U,
0xffc00b31U, 0x68581511U,
0x64f98fa7U, 0xbefa4fa4U,
)
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
val h = initial.copyOf()
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)
}
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 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

@@ -0,0 +1,124 @@
package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction
object `Blake-256` : HashFunction {
override val bytes: Int
get() = 32
override val block: Int
get() = 64
private val initial = uintArrayOf(
0x6a09e667U, 0xbb67ae85U,
0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU,
0x1f83d9abU, 0x5be0cd19U,
)
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
val h = initial.copyOf()
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)
}
return h.toUByteArray()
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value)
add(0x80U)
while (size % 64 != 55) {
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..<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

@@ -0,0 +1,123 @@
package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction
object `Blake-384` : HashFunction {
override val bytes: Int
get() = 48
override val block: Int
get() = 128
private val initial = ulongArrayOf(
0xcbbb9d5dc1059ed8U, 0x629a292a367cd507U,
0x9159015a3070dd17U, 0x152fecd8f70e5939U,
0x67332667ffc00b31U, 0x8eb44a8768581511U,
0xdb0c2e0d64f98fa7U, 0x47b5481dbefa4fa4U,
)
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
val h = initial.copyOf()
var t = 0UL
val blocks = pad(value)
.chunked(128) { it.toUByteArray() }
for (block in blocks) {
t += minOf(l - t, 1024UL)
compress(h, block, t)
}
return h.sliceArray(0..5).toUByteArray()
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value)
add(0x80U)
while (size % 128 != 120) {
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

@@ -0,0 +1,125 @@
package com.infendro.hash.blake
import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction
object `Blake-512` : HashFunction {
override val bytes: Int
get() = 64
override val block: Int
get() = 128
private val initial = ulongArrayOf(
0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL,
0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL,
0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL,
)
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
val h = initial.copyOf()
var t = 0UL
val blocks = pad(value)
.chunked(128) { it.toUByteArray() }
for (block in blocks) {
t += minOf(l - t, 1024UL)
compress(h, block, t)
}
return h.toUByteArray()
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value)
add(0x80U)
while (size % 128 != 111) {
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..<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

@@ -0,0 +1,116 @@
package com.infendro.hash.blake2
import com.infendro.bytearray.ByteOrder
import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction
class Blake2b(
override val bytes: Int,
) : HashFunction {
init {
require(bytes in 1..64)
}
override val block: Int
get() = 128
private val initial = ulongArrayOf(
0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL,
0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL,
0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL,
)
private val sigma = arrayOf(
intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
intArrayOf(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
intArrayOf(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4),
intArrayOf(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8),
intArrayOf(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13),
intArrayOf(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9),
intArrayOf(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11),
intArrayOf(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10),
intArrayOf(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5),
intArrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0),
)
override fun hash(value: UByteArray): UByteArray {
val l = value.size.toULong()
val h = initial.copyOf()
h[0] = h[0] xor (0x01010000UL or bytes.toULong())
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)
}
return h.toUByteArray(ByteOrder.LITTLE_ENDIAN).sliceArray(0..<bytes)
}
private fun pad(
value: UByteArray,
): UByteArray {
return buildList {
addAll(value)
if (isEmpty()) add(0x00U)
while (size % 128 != 0) {
add(0x00U)
}
}.toUByteArray()
}
private fun compress(
h: ULongArray,
block: UByteArray,
t: ULong,
last: Boolean,
) {
val m = block.toULongArray()
val v = ULongArray(16)
for (i in 0..<8) v[i] = h[i]
for (i in 0..<8) v[i + 8] = initial[i]
v[12] = v[12] xor t
if (last) v[14] = v[14].inv()
repeat(12) { r ->
val s = sigma[r % 10]
mix(v, 0, 4, 8, 12, m[s[0]], m[s[1]])
mix(v, 1, 5, 9, 13, m[s[2]], m[s[3]])
mix(v, 2, 6, 10, 14, m[s[4]], m[s[5]])
mix(v, 3, 7, 11, 15, m[s[6]], m[s[7]])
mix(v, 0, 5, 10, 15, m[s[8]], m[s[9]])
mix(v, 1, 6, 11, 12, m[s[10]], m[s[11]])
mix(v, 2, 7, 8, 13, m[s[12]], m[s[13]])
mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]])
}
for (i in 0..7) {
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,
) {
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(24)
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(63)
}
}

View File

@@ -0,0 +1,117 @@
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.hash.HashFunction
class Blake2s(
override val bytes: Int,
) : HashFunction {
init {
require(bytes in 1..32)
}
override val block: Int
get() = 64
private val initial = uintArrayOf(
0x6a09e667U, 0xbb67ae85U,
0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU,
0x1f83d9abU, 0x5be0cd19U,
)
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()
val h = initial.copyOf()
h[0] = h[0] xor (0x01010000U or bytes.toUInt())
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)
}
return h.toUByteArray(LITTLE_ENDIAN).sliceArray(0..<bytes)
}
private fun pad(
value: UByteArray,
): UByteArray {
return buildList {
addAll(value)
if (isEmpty()) add(0x00U)
while (size % 64 != 0) {
add(0x00U)
}
}.toUByteArray()
}
private fun compress(
h: UIntArray,
block: UByteArray,
t: UInt,
last: Boolean,
) {
val m = block.toUIntArray()
val v = UIntArray(16)
for (i in 0..<8) v[i] = h[i]
for (i in 0..<8) v[i + 8] = initial[i]
v[12] = v[12] xor t
if (last) v[14] = v[14].inv()
repeat(10) { r ->
val s = sigma[r]
mix(v, 0, 4, 8, 12, m[s[0]], m[s[1]])
mix(v, 1, 5, 9, 13, m[s[2]], m[s[3]])
mix(v, 2, 6, 10, 14, m[s[4]], m[s[5]])
mix(v, 3, 7, 11, 15, m[s[6]], m[s[7]])
mix(v, 0, 5, 10, 15, m[s[8]], m[s[9]])
mix(v, 1, 6, 11, 12, m[s[10]], m[s[11]])
mix(v, 2, 7, 8, 13, m[s[12]], m[s[13]])
mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]])
}
for (i in 0..7) {
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,
) {
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

@@ -6,10 +6,11 @@ import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
import kotlin.math.min import kotlin.math.min
abstract class Keccak internal constructor( abstract class Keccak(
override val bytes: Int,
private val rate: Int, private val rate: Int,
private val domain: UByte, private val domain: UByte,
) : HashFunction() { ) : HashFunction {
override val block: Int override val block: Int
get() = rate get() = rate
@@ -19,7 +20,7 @@ abstract class Keccak internal constructor(
0x000000000000008aUL, 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000aUL, 0x000000000000008aUL, 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000aUL,
0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL, 0x000000008000808bUL, 0x800000000000008bUL, 0x8000000000008089UL, 0x8000000000008003UL,
0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL, 0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800aUL, 0x800000008000000aUL,
0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL 0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL,
) )
private val rotation = arrayOf( private val rotation = arrayOf(
@@ -33,45 +34,41 @@ abstract class Keccak internal constructor(
override fun hash( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
val paddedValue = buildList { val state = ULongArray(25)
val blocks = pad(value)
.chunked(rate) { it.toUByteArray() }
for (block in blocks) {
absorb(state, block)
}
return squeeze(state)
}
private fun pad(
value: UByteArray,
): UByteArray {
return buildList {
addAll(value) addAll(value)
add(domain) add(domain)
while ((size % rate) != (rate - 1)) { while ((size % rate) != (rate - 1)) {
add(0x00U) add(0x00U)
} }
add(0x80U) add(0x80U)
}.toUByteArray()
} }
val state = ULongArray(25) private fun absorb(
state: ULongArray,
// absorb block: UByteArray,
val chunks = paddedValue ) {
.chunked(rate) { it.toUByteArray() } val numbers = block.toULongArray(LITTLE_ENDIAN)
for (chunk in chunks) {
val numbers = chunk.toULongArray(LITTLE_ENDIAN)
for ((i, number) in numbers.withIndex()) { for ((i, number) in numbers.withIndex()) {
state[i] = state[i] xor number state[i] = state[i] xor number
} }
permute(state) permute(state)
} }
// squeeze
return buildList {
var i = 0
while (size < bytes) {
if (i == rate / 8) {
permute(state)
i = 0
}
addAll(
state[i++].toUByteArray(LITTLE_ENDIAN)
.take(min(bytes - size, 8))
)
}
}.toUByteArray()
}
private fun permute( private fun permute(
a: ULongArray, a: ULongArray,
) { ) {
@@ -105,4 +102,22 @@ abstract class Keccak internal constructor(
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,7 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-224` : Keccak(144, 0x06U) { object `SHA3-224` : Keccak(28, 144, 0x06U)
override val bytes: Int
get() = 28
}

View File

@@ -2,7 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-256` : Keccak(136, 0x06U) { object `SHA3-256` : Keccak(32, 136, 0x06U)
override val bytes: Int
get() = 32
}

View File

@@ -2,7 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-384` : Keccak(104, 0x06U) { object `SHA3-384` : Keccak(48, 104, 0x06U)
override val bytes: Int
get() = 48
}

View File

@@ -2,7 +2,4 @@ package com.infendro.hash.keccak.sha3
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
object `SHA3-512` : Keccak(72, 0x06U) { object `SHA3-512` : Keccak(64, 72, 0x06U)
override val bytes: Int
get() = 64
}

View File

@@ -3,5 +3,5 @@ package com.infendro.hash.keccak.shake
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
class SHAKE128( class SHAKE128(
override val bytes: Int, bytes: Int,
) : Keccak(168, 0x1FU) ) : Keccak(bytes, 168, 0x1FU)

View File

@@ -3,5 +3,5 @@ package com.infendro.hash.keccak.shake
import com.infendro.hash.keccak.Keccak import com.infendro.hash.keccak.Keccak
class SHAKE256( class SHAKE256(
override val bytes: Int, bytes: Int,
) : Keccak(136, 0x1FU) ) : Keccak(bytes, 136, 0x1FU)

View File

@@ -5,33 +5,30 @@ import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toUIntArray import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object MD5 : HashFunction() { object MD5 : HashFunction {
override val bytes: Int override val bytes: Int
get() = 16 get() = 16
override val block: Int override val block: Int
get() = 64 get() = 64
private val s = intArrayOf( private val initial = uintArrayOf(
7, 12, 17, 22, 0x67452301U, 0xefcdab89U,
7, 12, 17, 22, 0x98badcfeU, 0x10325476U,
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 k = uintArrayOf( 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(
0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU, 0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU,
0xf57c0fafU, 0x4787c62aU, 0xa8304613U, 0xfd469501U, 0xf57c0fafU, 0x4787c62aU, 0xa8304613U, 0xfd469501U,
0x698098d8U, 0x8b44f7afU, 0xffff5bb1U, 0x895cd7beU, 0x698098d8U, 0x8b44f7afU, 0xffff5bb1U, 0x895cd7beU,
@@ -53,39 +50,44 @@ object MD5 : HashFunction() {
override fun hash( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
var a0 = 0x67452301U val h = initial.copyOf()
var b0 = 0xefcdab89U
var c0 = 0x98badcfeU
var d0 = 0x10325476U
val ml = value.size.toULong() * 8UL
val paddedValue = buildList { val blocks = pad(value)
.chunked(64) { it.toUByteArray() }
for (block in blocks) {
process(h, block)
}
return h.toUByteArray(LITTLE_ENDIAN)
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value) addAll(value)
add(0x80U) add(0x80U)
while (size % 64 != 56) { while (size % 64 != 56) {
add(0x00U) add(0x00U)
} }
addAll(ml.toUByteArray(LITTLE_ENDIAN)) addAll(l.toUByteArray(LITTLE_ENDIAN))
}.toUByteArray()
} }
val chunks = paddedValue private fun process(
.chunked(64) { it.toUByteArray() } h: UIntArray,
for (chunk in chunks) { block: UByteArray,
val w = buildList { ) {
addAll(chunk.toUIntArray(LITTLE_ENDIAN)) val w = block.toUIntArray(LITTLE_ENDIAN)
} val v = h.copyOf()
var a = a0 repeat(64) { i ->
var b = b0 var f = when (i) {
var c = c0 in 0..15 -> (v[1] and v[2]) or (v[1].inv() and v[3])
var d = d0 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]
for (i in 0..<64) { else -> v[2] xor (v[1] or v[3].inv())
val f = when (i) {
in 0..15 -> (b and c) or (b.inv() and d)
in 16..31 -> (d and b) or (d.inv() and c)
in 32..47 -> b xor c xor d
else -> c xor (b or d.inv())
} }
val g = when (i) { val g = when (i) {
in 0..15 -> i in 0..15 -> i
@@ -93,24 +95,15 @@ object MD5 : HashFunction() {
in 32..47 -> (3 * i + 5) % 16 in 32..47 -> (3 * i + 5) % 16
else -> (7 * i) % 16 else -> (7 * i) % 16
} }
val temp = a f += v[0] + c[i] + w[g]
a = d v[0] = v[3]
d = c v[3] = v[2]
c = b v[2] = v[1]
b += (temp + f + k[i] + w[g]).rotateLeft(s[i]) v[1] += f.rotateLeft(shifts[i])
} }
a0 += a for (i in 0..3) {
b0 += b h[i] += v[i]
c0 += c
d0 += d
} }
return ubyteArrayOf(
*a0.toUByteArray(LITTLE_ENDIAN),
*b0.toUByteArray(LITTLE_ENDIAN),
*c0.toUByteArray(LITTLE_ENDIAN),
*d0.toUByteArray(LITTLE_ENDIAN),
)
} }
} }

View File

@@ -4,55 +4,66 @@ import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toUIntArray import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object SHA1 : HashFunction() { object SHA1 : HashFunction {
override val bytes: Int override val bytes: Int
get() = 20 get() = 20
override val block: Int override val block: Int
get() = 64 get() = 64
private val initial = uintArrayOf(
0x67452301U, 0xefcdaB89U,
0x98badcfeU, 0x10325476U,
0xc3d2e1f0U,
)
override fun hash( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
var h0 = 0x67452301U val h = initial.copyOf()
var h1 = 0xefcdaB89U
var h2 = 0x98badcfeU
var h3 = 0x10325476U
var h4 = 0xc3d2e1f0U
val ml = value.size.toULong() * 8UL
val paddedValue = buildList { val blocks = pad(value)
.chunked(64) { it.toUByteArray() }
for (block in blocks) {
process(h, block)
}
return h.toUByteArray()
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value) addAll(value)
add(0x80U) add(0x80U)
while (size % 64 != 56) { while (size % 64 != 56) {
add(0x00U) add(0x00U)
} }
addAll(ml.toUByteArray()) addAll(l.toUByteArray())
}.toUByteArray()
} }
val chunks = paddedValue private fun process(
.chunked(64) { it.toUByteArray() } h: UIntArray,
for (chunk in chunks) { block: UByteArray,
) {
val w = buildList { val w = buildList {
addAll(chunk.toUIntArray()) addAll(block.toUIntArray())
for (i in 16..<80) { for (i in 16..79) {
val word = (get(i - 3) xor get(i - 8) xor get(i - 14) xor get(i - 16)).rotateLeft(1) val word = (get(i - 3) xor get(i - 8) xor get(i - 14) xor get(i - 16)).rotateLeft(1)
add(word) add(word)
} }
} }.toUIntArray()
val v = h.copyOf()
var a = h0 repeat(80) { i ->
var b = h1
var c = h2
var d = h3
var e = h4
for (i in 0..<80) {
val f = when (i) { val f = when (i) {
in 0..<20 -> (b and c) or (b.inv() and d) in 0..<20 -> (v[1] and v[2]) or (v[1].inv() and v[3])
in 20..<40 -> b xor c xor d in 20..<40 -> v[1] xor v[2] xor v[3]
in 40..<60 -> (b and c) or (b and d) or (c and d) in 40..<60 -> (v[1] and v[2]) or (v[1] and v[3]) or (v[2] and v[3])
else -> b xor c xor d else -> v[1] xor v[2] xor v[3]
} }
val k = when (i) { val k = when (i) {
in 0..<20 -> 0x5a827999U in 0..<20 -> 0x5a827999U
@@ -60,27 +71,16 @@ object SHA1 : HashFunction() {
in 40..<60 -> 0x8f1bbcdcU in 40..<60 -> 0x8f1bbcdcU
else -> 0xca62c1d6U else -> 0xca62c1d6U
} }
val temp = a.rotateLeft(5) + f + e + k + w[i] val temp = v[0].rotateLeft(5) + f + v[4] + k + w[i]
e = d v[4] = v[3]
d = c v[3] = v[2]
c = b.rotateLeft(30) v[2] = v[1].rotateLeft(30)
b = a v[1] = v[0]
a = temp v[0] = temp
} }
h0 += a for (i in 0..4) {
h1 += b h[i] += v[i]
h2 += c
h3 += d
h4 += e
} }
return ubyteArrayOf(
*h0.toUByteArray(),
*h1.toUByteArray(),
*h2.toUByteArray(),
*h3.toUByteArray(),
*h4.toUByteArray(),
)
} }
} }

View File

@@ -4,14 +4,21 @@ import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toUIntArray import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object `SHA-224` : HashFunction() { object `SHA-224` : HashFunction {
override val bytes: Int override val bytes: Int
get() = 28 get() = 28
override val block: Int override val block: Int
get() = 64 get() = 64
private val k = uintArrayOf( private val initial = uintArrayOf(
0xc1059ed8U, 0x367cd507U,
0x3070dd17U, 0xf70e5939U,
0xffc00b31U, 0x68581511U,
0x64f98fa7U, 0xbefa4fa4U,
)
private val c = uintArrayOf(
0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U, 0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U,
0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU,
@@ -25,82 +32,65 @@ object `SHA-224` : HashFunction() {
override fun hash( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
var h0 = 0xc1059ed8U val h = initial.copyOf()
var h1 = 0x367cd507U
var h2 = 0x3070dd17U
var h3 = 0xf70e5939U
var h4 = 0xffc00b31U
var h5 = 0x68581511U
var h6 = 0x64f98fa7U
var h7 = 0xbefa4fa4U
val ml = value.size.toULong() * 8UL
val paddedValue = buildList { 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) addAll(value)
add(0x80U) add(0x80U)
while (size % 64 != 56) { while (size % 64 != 56) {
add(0x00U) add(0x00U)
} }
addAll(ml.toUByteArray()) addAll(l.toUByteArray())
}.toUByteArray()
} }
val chunks = paddedValue private fun process(
.chunked(64) { it.toUByteArray() } h: UIntArray,
for (chunk in chunks) { block: UByteArray,
) {
val w = buildList { val w = buildList {
addAll(chunk.toUIntArray()) addAll(block.toUIntArray())
for (i in 16..<64) { 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 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) 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) add(get(i - 16) + s0 + get(i - 7) + s1)
} }
} }.toUIntArray()
val v = h.copyOf()
var a = h0 repeat(64) { i ->
var b = h1 val s0 = v[0].rotateRight(2) xor v[0].rotateRight(13) xor v[0].rotateRight(22)
var c = h2 val s1 = v[4].rotateRight(6) xor v[4].rotateRight(11) xor v[4].rotateRight(25)
var d = h3 val ch = (v[4] and v[5]) xor (v[4].inv() and v[6])
var e = h4 val temp1 = v[7] + s1 + ch + this.c[i] + w[i]
var f = h5 val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2])
var g = h6
var h = h7
for (i in 0..<64) {
val s0 = a.rotateRight(2) xor a.rotateRight(13) xor a.rotateRight(22)
val s1 = e.rotateRight(6) xor e.rotateRight(11) xor e.rotateRight(25)
val ch = (e and f) xor (e.inv() and g)
val temp1 = h + s1 + ch + k[i] + w[i]
val maj = (a and b) xor (a and c) xor (b and c)
val temp2 = s0 + maj val temp2 = s0 + maj
h = g v[7] = v[6]
g = f v[6] = v[5]
f = e v[5] = v[4]
e = d + temp1 v[4] = v[3] + temp1
d = c v[3] = v[2]
c = b v[2] = v[1]
b = a v[1] = v[0]
a = temp1 + temp2 v[0] = temp1 + temp2
} }
h0 += a for (i in 0..7) {
h1 += b h[i] += v[i]
h2 += c
h3 += d
h4 += e
h5 += f
h6 += g
h7 += h
} }
return ubyteArrayOf(
*h0.toUByteArray(),
*h1.toUByteArray(),
*h2.toUByteArray(),
*h3.toUByteArray(),
*h4.toUByteArray(),
*h5.toUByteArray(),
*h6.toUByteArray(),
)
} }
} }

View File

@@ -4,14 +4,21 @@ import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toUIntArray import com.infendro.bytearray.toUIntArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object `SHA-256` : HashFunction() { object `SHA-256` : HashFunction {
override val bytes: Int override val bytes: Int
get() = 32 get() = 32
override val block: Int override val block: Int
get() = 64 get() = 64
private val k = uintArrayOf( private val initial = uintArrayOf(
0x6a09e667U, 0xbb67ae85U,
0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU,
0x1f83d9abU, 0x5be0cd19U,
)
private val c = uintArrayOf(
0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U, 0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U,
0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU,
@@ -25,83 +32,65 @@ object `SHA-256` : HashFunction() {
override fun hash( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
var h0 = 0x6a09e667U val h = initial.copyOf()
var h1 = 0xbb67ae85U
var h2 = 0x3c6ef372U
var h3 = 0xa54ff53aU
var h4 = 0x510e527fU
var h5 = 0x9b05688cU
var h6 = 0x1f83d9abU
var h7 = 0x5be0cd19U
val ml = value.size.toULong() * 8UL
val paddedValue = buildList { val blocks = pad(value)
.chunked(64) { it.toUByteArray() }
for (block in blocks) {
process(h, block)
}
return h.toUByteArray()
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value) addAll(value)
add(0x80U) add(0x80U)
while (size % 64 != 56) { while (size % 64 != 56) {
add(0x00U) add(0x00U)
} }
addAll(ml.toUByteArray()) addAll(l.toUByteArray())
}.toUByteArray()
} }
val chunks = paddedValue private fun process(
.chunked(64) { it.toUByteArray() } h: UIntArray,
for (chunk in chunks) { block: UByteArray,
) {
val w = buildList { val w = buildList {
addAll(chunk.toUIntArray()) addAll(block.toUIntArray())
for (i in 16..<64) { 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 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) 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) add(get(i - 16) + s0 + get(i - 7) + s1)
} }
} }.toUIntArray()
val v = h.copyOf()
var a = h0 repeat(64) { i ->
var b = h1 val s0 = v[0].rotateRight(2) xor v[0].rotateRight(13) xor v[0].rotateRight(22)
var c = h2 val s1 = v[4].rotateRight(6) xor v[4].rotateRight(11) xor v[4].rotateRight(25)
var d = h3 val ch = (v[4] and v[5]) xor (v[4].inv() and v[6])
var e = h4 val temp1 = v[7] + s1 + ch + this.c[i] + w[i]
var f = h5 val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2])
var g = h6
var h = h7
for (i in 0..<64) {
val s0 = a.rotateRight(2) xor a.rotateRight(13) xor a.rotateRight(22)
val s1 = e.rotateRight(6) xor e.rotateRight(11) xor e.rotateRight(25)
val ch = (e and f) xor (e.inv() and g)
val temp1 = h + s1 + ch + k[i] + w[i]
val maj = (a and b) xor (a and c) xor (b and c)
val temp2 = s0 + maj val temp2 = s0 + maj
h = g v[7] = v[6]
g = f v[6] = v[5]
f = e v[5] = v[4]
e = d + temp1 v[4] = v[3] + temp1
d = c v[3] = v[2]
c = b v[2] = v[1]
b = a v[1] = v[0]
a = temp1 + temp2 v[0] = temp1 + temp2
} }
h0 += a for (i in 0..7) {
h1 += b h[i] += v[i]
h2 += c
h3 += d
h4 += e
h5 += f
h6 += g
h7 += h
} }
return ubyteArrayOf(
*h0.toUByteArray(),
*h1.toUByteArray(),
*h2.toUByteArray(),
*h3.toUByteArray(),
*h4.toUByteArray(),
*h5.toUByteArray(),
*h6.toUByteArray(),
*h7.toUByteArray(),
)
} }
} }

View File

@@ -4,110 +4,105 @@ import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toULongArray import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object `SHA-384` : HashFunction() { object `SHA-384` : HashFunction {
override val bytes: Int override val bytes: Int
get() = 48 get() = 48
override val block: Int override val block: Int
get() = 128 get() = 128
private val k = ulongArrayOf( private val initial = ulongArrayOf(
0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, 0x3956c25bf348b538UL, 0xcbbb9d5dc1059ed8UL, 0x629a292a367cd507UL,
0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL, 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x9159015a3070dd17UL, 0x152fecd8f70e5939UL,
0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL, 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0x67332667ffc00b31UL, 0x8eb44a8768581511UL,
0xc19bf174cf692694UL, 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL, 0xdb0c2e0d64f98fa7UL, 0x47b5481dbefa4fa4UL,
0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL, 0x983e5152ee66dfabUL, )
0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL, 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL,
0x06ca6351e003826fUL, 0x142929670a0e6e70UL, 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, 0x4d2c6dfc5ac42aedUL, private val c = ulongArrayOf(
0x53380d139d95b3dfUL, 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, 0x81c2c92e47edaee6UL, 0x92722c851482353bUL, 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL, 0xd192e819d6ef5218UL, 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
0xd69906245565a910UL, 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL, 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL, 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, 0x5b9cca4f7763e373UL, 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
0x682e6ff3d6b2b8a3UL, 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL, 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
0x90befffa23631e28UL, 0xa4506cebde82bde9UL, 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL, 0xca273eceea26619cUL, 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
0xd186b8c721c0c207UL, 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL, 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
0x113f9804bef90daeUL, 0x1b710b35131c471bUL, 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, 0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
0x431d67c49c100d4cUL, 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL, 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( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
var h0 = 0xcbbb9d5dc1059ed8UL val h = initial.copyOf()
var h1 = 0x629a292a367cd507UL
var h2 = 0x9159015a3070dd17UL
var h3 = 0x152fecd8f70e5939UL
var h4 = 0x67332667ffc00b31UL
var h5 = 0x8eb44a8768581511UL
var h6 = 0xdb0c2e0d64f98fa7UL
var h7 = 0x47b5481dbefa4fa4UL
val ml = value.size.toULong() * 8UL
val paddedValue = buildList { 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) addAll(value)
add(0x80U) add(0x80U)
while (size % 128 != 120) { while (size % 128 != 120) {
add(0x00U) add(0x00U)
} }
addAll(ml.toUByteArray()) addAll(l.toUByteArray())
}.toUByteArray()
} }
val chunks = paddedValue private fun process(
.chunked(128) { it.toUByteArray() } h: ULongArray,
for (chunk in chunks) { block: UByteArray,
) {
val w = buildList { val w = buildList {
addAll(chunk.toULongArray()) addAll(block.toULongArray())
for (i in 16..<80) { 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 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) 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) add(get(i - 16) + s0 + get(i - 7) + s1)
} }
} }.toULongArray()
val v = h.copyOf()
var a = h0 repeat(80) { i ->
var b = h1 val s0 = v[0].rotateRight(28) xor v[0].rotateRight(34) xor v[0].rotateRight(39)
var c = h2 val s1 = v[4].rotateRight(14) xor v[4].rotateRight(18) xor v[4].rotateRight(41)
var d = h3 val ch = (v[4] and v[5]) xor (v[4].inv() and v[6])
var e = h4 val temp1 = v[7] + s1 + ch + this.c[i] + w[i]
var f = h5 val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2])
var g = h6
var h = h7
for (i in 0..<80) {
val s0 = a.rotateRight(28) xor a.rotateRight(34) xor a.rotateRight(39)
val s1 = e.rotateRight(14) xor e.rotateRight(18) xor e.rotateRight(41)
val ch = (e and f) xor (e.inv() and g)
val temp1 = h + s1 + ch + k[i] + w[i]
val maj = (a and b) xor (a and c) xor (b and c)
val temp2 = s0 + maj val temp2 = s0 + maj
h = g v[7] = v[6]
g = f v[6] = v[5]
f = e v[5] = v[4]
e = d + temp1 v[4] = v[3] + temp1
d = c v[3] = v[2]
c = b v[2] = v[1]
b = a v[1] = v[0]
a = temp1 + temp2 v[0] = temp1 + temp2
} }
h0 += a for (i in 0..7) {
h1 += b h[i] += v[i]
h2 += c
h3 += d
h4 += e
h5 += f
h6 += g
h7 += h
} }
return ubyteArrayOf(
*h0.toUByteArray(),
*h1.toUByteArray(),
*h2.toUByteArray(),
*h3.toUByteArray(),
*h4.toUByteArray(),
*h5.toUByteArray(),
)
} }
} }

View File

@@ -4,112 +4,105 @@ import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toULongArray import com.infendro.bytearray.toULongArray
import com.infendro.hash.HashFunction import com.infendro.hash.HashFunction
object `SHA-512` : HashFunction() { object `SHA-512` : HashFunction {
override val bytes: Int override val bytes: Int
get() = 64 get() = 64
override val block: Int override val block: Int
get() = 128 get() = 128
private val k = ulongArrayOf( private val initial = ulongArrayOf(
0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, 0x3956c25bf348b538UL, 0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL,
0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL, 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL,
0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL, 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
0xc19bf174cf692694UL, 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL, 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL,
0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL, 0x983e5152ee66dfabUL, )
0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL, 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL,
0x06ca6351e003826fUL, 0x142929670a0e6e70UL, 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, 0x4d2c6dfc5ac42aedUL, private val c = ulongArrayOf(
0x53380d139d95b3dfUL, 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, 0x81c2c92e47edaee6UL, 0x92722c851482353bUL, 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL,
0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL, 0xd192e819d6ef5218UL, 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL,
0xd69906245565a910UL, 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL, 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL,
0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL, 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, 0x5b9cca4f7763e373UL, 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL,
0x682e6ff3d6b2b8a3UL, 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL, 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL,
0x90befffa23631e28UL, 0xa4506cebde82bde9UL, 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL, 0xca273eceea26619cUL, 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL,
0xd186b8c721c0c207UL, 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL, 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL,
0x113f9804bef90daeUL, 0x1b710b35131c471bUL, 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, 0x06ca6351e003826fUL, 0x142929670a0e6e70UL,
0x431d67c49c100d4cUL, 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL, 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( override fun hash(
value: UByteArray, value: UByteArray,
): UByteArray { ): UByteArray {
var h0 = 0x6a09e667f3bcc908UL val h = initial.copyOf()
var h1 = 0xbb67ae8584caa73bUL
var h2 = 0x3c6ef372fe94f82bUL
var h3 = 0xa54ff53a5f1d36f1UL
var h4 = 0x510e527fade682d1UL
var h5 = 0x9b05688c2b3e6c1fUL
var h6 = 0x1f83d9abfb41bd6bUL
var h7 = 0x5be0cd19137e2179UL
val ml = value.size.toULong() * 8UL
val paddedValue = buildList { val blocks = pad(value)
.chunked(128) { it.toUByteArray() }
for (block in blocks) {
process(h, block)
}
return h.toUByteArray()
}
private fun pad(
value: UByteArray,
): UByteArray {
val l = value.size.toULong() * 8UL
return buildList {
addAll(value) addAll(value)
add(0x80U) add(0x80U)
while (size % 128 != 120) { while (size % 128 != 120) {
add(0x00U) add(0x00U)
} }
addAll(ml.toUByteArray()) addAll(l.toUByteArray())
}.toUByteArray()
} }
val chunks = paddedValue private fun process(
.chunked(128) { it.toUByteArray() } h: ULongArray,
for (chunk in chunks) { block: UByteArray,
) {
val w = buildList { val w = buildList {
addAll(chunk.toULongArray()) addAll(block.toULongArray())
for (i in 16..<80) { 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 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) 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) add(get(i - 16) + s0 + get(i - 7) + s1)
} }
} }.toULongArray()
val v = h.copyOf()
var a = h0 repeat(80) { i ->
var b = h1 val s0 = v[0].rotateRight(28) xor v[0].rotateRight(34) xor v[0].rotateRight(39)
var c = h2 val s1 = v[4].rotateRight(14) xor v[4].rotateRight(18) xor v[4].rotateRight(41)
var d = h3 val ch = (v[4] and v[5]) xor (v[4].inv() and v[6])
var e = h4 val temp1 = v[7] + s1 + ch + this.c[i] + w[i]
var f = h5 val maj = (v[0] and v[1]) xor (v[0] and v[2]) xor (v[1] and v[2])
var g = h6
var h = h7
for (i in 0..<80) {
val s0 = a.rotateRight(28) xor a.rotateRight(34) xor a.rotateRight(39)
val s1 = e.rotateRight(14) xor e.rotateRight(18) xor e.rotateRight(41)
val ch = (e and f) xor (e.inv() and g)
val temp1 = h + s1 + ch + k[i] + w[i]
val maj = (a and b) xor (a and c) xor (b and c)
val temp2 = s0 + maj val temp2 = s0 + maj
h = g v[7] = v[6]
g = f v[6] = v[5]
f = e v[5] = v[4]
e = d + temp1 v[4] = v[3] + temp1
d = c v[3] = v[2]
c = b v[2] = v[1]
b = a v[1] = v[0]
a = temp1 + temp2 v[0] = temp1 + temp2
} }
h0 += a for (i in 0..7) {
h1 += b h[i] += v[i]
h2 += c
h3 += d
h4 += e
h5 += f
h6 += g
h7 += h
} }
return ubyteArrayOf(
*h0.toUByteArray(),
*h1.toUByteArray(),
*h2.toUByteArray(),
*h3.toUByteArray(),
*h4.toUByteArray(),
*h5.toUByteArray(),
*h6.toUByteArray(),
*h7.toUByteArray(),
)
} }
} }

View File

@@ -0,0 +1,67 @@
package com.infendro.hash.blake
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake-224 Test` {
val function = `Blake-224`
@Test
fun `bytes and block`() {
assertEquals(28, function.bytes)
assertEquals(224, function.bits)
assertEquals(64, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0x7dU, 0xc5U, 0x31U, 0x3bU,
0x1cU, 0x04U, 0x51U, 0x2aU,
0x17U, 0x4bU, 0xd6U, 0x50U,
0x3bU, 0x89U, 0x60U, 0x7aU,
0xecU, 0xbeU, 0xe0U, 0x90U,
0x3dU, 0x40U, 0xa8U, 0xa5U,
0x69U, 0xc9U, 0x4eU, 0xedU,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
@Test
fun `one block`() {
val expected = ubyteArrayOf(
0x45U, 0x04U, 0xcbU, 0x03U,
0x14U, 0xfbU, 0x2aU, 0x4fU,
0x7aU, 0x69U, 0x2eU, 0x69U,
0x6eU, 0x48U, 0x79U, 0x12U,
0xfeU, 0x3fU, 0x24U, 0x68U,
0xfeU, 0x31U, 0x2cU, 0x73U,
0xa5U, 0x27U, 0x8eU, 0xc5U,
)
val actual = function.hash(
UByteArray(1)
)
assertContentEquals(expected, actual)
}
@Test
fun `two blocks`() {
val expected = ubyteArrayOf(
0xf5U, 0xaaU, 0x00U, 0xddU,
0x1cU, 0xb8U, 0x47U, 0xe3U,
0x14U, 0x03U, 0x72U, 0xafU,
0x7bU, 0x5cU, 0x46U, 0xb4U,
0x88U, 0x8dU, 0x82U, 0xc8U,
0xc0U, 0xa9U, 0x17U, 0x91U,
0x3cU, 0xfbU, 0x5dU, 0x04U,
)
val actual = function.hash(
UByteArray(72)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,70 @@
package com.infendro.hash.blake
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake-256 Test` {
val function = `Blake-256`
@Test
fun `bytes and block`() {
assertEquals(32, function.bytes)
assertEquals(256, function.bits)
assertEquals(64, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0x71U, 0x6fU, 0x6eU, 0x86U,
0x3fU, 0x74U, 0x4bU, 0x9aU,
0xc2U, 0x2cU, 0x97U, 0xecU,
0x7bU, 0x76U, 0xeaU, 0x5fU,
0x59U, 0x08U, 0xbcU, 0x5bU,
0x2fU, 0x67U, 0xc6U, 0x15U,
0x10U, 0xbfU, 0xc4U, 0x75U,
0x13U, 0x84U, 0xeaU, 0x7aU,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
@Test
fun `one block`() {
val expected = ubyteArrayOf(
0x0cU, 0xe8U, 0xd4U, 0xefU,
0x4dU, 0xd7U, 0xcdU, 0x8dU,
0x62U, 0xdfU, 0xdeU, 0xd9U,
0xd4U, 0xedU, 0xb0U, 0xa7U,
0x74U, 0xaeU, 0x6aU, 0x41U,
0x92U, 0x9aU, 0x74U, 0xdaU,
0x23U, 0x10U, 0x9eU, 0x8fU,
0x11U, 0x13U, 0x9cU, 0x87U,
)
val actual = function.hash(
UByteArray(1)
)
assertContentEquals(expected, actual)
}
@Test
fun `two blocks`() {
val expected = ubyteArrayOf(
0xd4U, 0x19U, 0xbaU, 0xd3U,
0x2dU, 0x50U, 0x4fU, 0xb7U,
0xd4U, 0x4dU, 0x46U, 0x0cU,
0x42U, 0xc5U, 0x59U, 0x3fU,
0xe5U, 0x44U, 0xfaU, 0x4cU,
0x13U, 0x5dU, 0xecU, 0x31U,
0xe2U, 0x1bU, 0xd9U, 0xabU,
0xdcU, 0xc2U, 0x2dU, 0x41U,
)
val actual = function.hash(
UByteArray(72)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,82 @@
package com.infendro.hash.blake
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake-384 Test` {
val function = `Blake-384`
@Test
fun `bytes and block`() {
assertEquals(48, function.bytes)
assertEquals(384, function.bits)
assertEquals(128, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0xc6U, 0xcbU, 0xd8U, 0x9cU,
0x92U, 0x6aU, 0xb5U, 0x25U,
0xc2U, 0x42U, 0xe6U, 0x62U,
0x1fU, 0x2fU, 0x5fU, 0xa7U,
0x3aU, 0xa4U, 0xafU, 0xe3U,
0xd9U, 0xe2U, 0x4aU, 0xedU,
0x72U, 0x7fU, 0xaaU, 0xadU,
0xd6U, 0xafU, 0x38U, 0xb6U,
0x20U, 0xbdU, 0xb6U, 0x23U,
0xddU, 0x2bU, 0x47U, 0x88U,
0xb1U, 0xc8U, 0x08U, 0x69U,
0x84U, 0xafU, 0x87U, 0x06U,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
@Test
fun `one block`() {
val expected = ubyteArrayOf(
0x10U, 0x28U, 0x1fU, 0x67U,
0xe1U, 0x35U, 0xe9U, 0x0aU,
0xe8U, 0xe8U, 0x82U, 0x25U,
0x1aU, 0x35U, 0x55U, 0x10U,
0xa7U, 0x19U, 0x36U, 0x7aU,
0xd7U, 0x02U, 0x27U, 0xb1U,
0x37U, 0x34U, 0x3eU, 0x1bU,
0xc1U, 0x22U, 0x01U, 0x5cU,
0x29U, 0x39U, 0x1eU, 0x85U,
0x45U, 0xb5U, 0x27U, 0x2dU,
0x13U, 0xa7U, 0xc2U, 0x87U,
0x9dU, 0xa3U, 0xd8U, 0x07U
)
val actual = function.hash(
UByteArray(1)
)
assertContentEquals(expected, actual)
}
@Test
fun `two blocks`() {
val expected = ubyteArrayOf(
0x0bU, 0x98U, 0x45U, 0xddU,
0x42U, 0x95U, 0x66U, 0xcdU,
0xabU, 0x77U, 0x2bU, 0xa1U,
0x95U, 0xd2U, 0x71U, 0xefU,
0xfeU, 0x2dU, 0x02U, 0x11U,
0xf1U, 0x69U, 0x91U, 0xd7U,
0x66U, 0xbaU, 0x74U, 0x94U,
0x47U, 0xc5U, 0xcdU, 0xe5U,
0x69U, 0x78U, 0x0bU, 0x2dU,
0xaaU, 0x66U, 0xc4U, 0xb2U,
0x24U, 0xa2U, 0xecU, 0x2eU,
0x5dU, 0x09U, 0x17U, 0x4cU
)
val actual = function.hash(
UByteArray(144)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,94 @@
package com.infendro.hash.blake
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake-512 Test` {
val function = `Blake-512`
@Test
fun `bytes and block`() {
assertEquals(64, function.bytes)
assertEquals(512, function.bits)
assertEquals(128, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0xa8U, 0xcfU, 0xbbU, 0xd7U,
0x37U, 0x26U, 0x06U, 0x2dU,
0xf0U, 0xc6U, 0x86U, 0x4dU,
0xdaU, 0x65U, 0xdeU, 0xfeU,
0x58U, 0xefU, 0x0cU, 0xc5U,
0x2aU, 0x56U, 0x25U, 0x09U,
0x0fU, 0xa1U, 0x76U, 0x01U,
0xe1U, 0xeeU, 0xcdU, 0x1bU,
0x62U, 0x8eU, 0x94U, 0xf3U,
0x96U, 0xaeU, 0x40U, 0x2aU,
0x00U, 0xacU, 0xc9U, 0xeaU,
0xb7U, 0x7bU, 0x4dU, 0x4cU,
0x2eU, 0x85U, 0x2aU, 0xaaU,
0xa2U, 0x5aU, 0x63U, 0x6dU,
0x80U, 0xafU, 0x3fU, 0xc7U,
0x91U, 0x3eU, 0xf5U, 0xb8U,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
@Test
fun `one block`() {
val expected = ubyteArrayOf(
0x97U, 0x96U, 0x15U, 0x87U,
0xf6U, 0xd9U, 0x70U, 0xfaU,
0xbaU, 0x6dU, 0x24U, 0x78U,
0x04U, 0x5dU, 0xe6U, 0xd1U,
0xfaU, 0xbdU, 0x09U, 0xb6U,
0x1aU, 0xe5U, 0x09U, 0x32U,
0x05U, 0x4dU, 0x52U, 0xbcU,
0x29U, 0xd3U, 0x1bU, 0xe4U,
0xffU, 0x91U, 0x02U, 0xb9U,
0xf6U, 0x9eU, 0x2bU, 0xbdU,
0xb8U, 0x3bU, 0xe1U, 0x3dU,
0x4bU, 0x9cU, 0x06U, 0x09U,
0x1eU, 0x5fU, 0xa0U, 0xb4U,
0x8bU, 0xd0U, 0x81U, 0xb6U,
0x34U, 0x05U, 0x8bU, 0xe0U,
0xecU, 0x49U, 0xbeU, 0xb3U,
)
val actual = function.hash(
UByteArray(1)
)
assertContentEquals(expected, actual)
}
@Test
fun `two blocks`() {
val expected = ubyteArrayOf(
0x31U, 0x37U, 0x17U, 0xd6U,
0x08U, 0xe9U, 0xcfU, 0x75U,
0x8dU, 0xcbU, 0x1eU, 0xb0U,
0xf0U, 0xc3U, 0xcfU, 0x9fU,
0xc1U, 0x50U, 0xb2U, 0xd5U,
0x00U, 0xfbU, 0x33U, 0xf5U,
0x1cU, 0x52U, 0xafU, 0xc9U,
0x9dU, 0x35U, 0x8aU, 0x2fU,
0x13U, 0x74U, 0xb8U, 0xa3U,
0x8bU, 0xbaU, 0x79U, 0x74U,
0xe7U, 0xf6U, 0xefU, 0x79U,
0xcaU, 0xb1U, 0x6fU, 0x22U,
0xceU, 0x1eU, 0x64U, 0x9dU,
0x6eU, 0x01U, 0xadU, 0x95U,
0x89U, 0xc2U, 0x13U, 0x04U,
0x5dU, 0x54U, 0x5dU, 0xdeU,
)
val actual = function.hash(
UByteArray(144)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,38 @@
package com.infendro.hash.blake2
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake2b-384 Test` {
val function = Blake2b(48)
@Test
fun `bytes and block`() {
assertEquals(48, function.bytes)
assertEquals(384, function.bits)
assertEquals(128, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0xb3U, 0x28U, 0x11U, 0x42U,
0x33U, 0x77U, 0xf5U, 0x2dU,
0x78U, 0x62U, 0x28U, 0x6eU,
0xe1U, 0xa7U, 0x2eU, 0xe5U,
0x40U, 0x52U, 0x43U, 0x80U,
0xfdU, 0xa1U, 0x72U, 0x4aU,
0x6fU, 0x25U, 0xd7U, 0x97U,
0x8cU, 0x6fU, 0xd3U, 0x24U,
0x4aU, 0x6cU, 0xafU, 0x04U,
0x98U, 0x81U, 0x26U, 0x73U,
0xc5U, 0xe0U, 0x5eU, 0xf5U,
0x83U, 0x82U, 0x51U, 0x00U,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,42 @@
package com.infendro.hash.blake2
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake2b-512 Test` {
val function = Blake2b(64)
@Test
fun `bytes and block`() {
assertEquals(64, function.bytes)
assertEquals(512, function.bits)
assertEquals(128, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0x78U, 0x6aU, 0x02U, 0xf7U,
0x42U, 0x01U, 0x59U, 0x03U,
0xc6U, 0xc6U, 0xfdU, 0x85U,
0x25U, 0x52U, 0xd2U, 0x72U,
0x91U, 0x2fU, 0x47U, 0x40U,
0xe1U, 0x58U, 0x47U, 0x61U,
0x8aU, 0x86U, 0xe2U, 0x17U,
0xf7U, 0x1fU, 0x54U, 0x19U,
0xd2U, 0x5eU, 0x10U, 0x31U,
0xafU, 0xeeU, 0x58U, 0x53U,
0x13U, 0x89U, 0x64U, 0x44U,
0x93U, 0x4eU, 0xb0U, 0x4bU,
0x90U, 0x3aU, 0x68U, 0x5bU,
0x14U, 0x48U, 0xb7U, 0x55U,
0xd5U, 0x6fU, 0x70U, 0x1aU,
0xfeU, 0x9bU, 0xe2U, 0xceU,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,33 @@
package com.infendro.hash.blake2
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake2s-224 Test` {
val function = Blake2s(28)
@Test
fun `bytes and block`() {
assertEquals(28, function.bytes)
assertEquals(224, function.bits)
assertEquals(64, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0x1fU, 0xa1U, 0x29U, 0x1eU,
0x65U, 0x24U, 0x8bU, 0x37U,
0xb3U, 0x43U, 0x34U, 0x75U,
0xb2U, 0xa0U, 0xddU, 0x63U,
0xd5U, 0x4aU, 0x11U, 0xecU,
0xc4U, 0xe3U, 0xe0U, 0x34U,
0xe7U, 0xbcU, 0x1eU, 0xf4U,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
}

View File

@@ -0,0 +1,34 @@
package com.infendro.hash.blake2
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class `Blake2s-256 Test` {
val function = Blake2s(32)
@Test
fun `bytes and block`() {
assertEquals(32, function.bytes)
assertEquals(256, function.bits)
assertEquals(64, function.block)
}
@Test
fun `empty bytearray`() {
val expected = ubyteArrayOf(
0x69U, 0x21U, 0x7aU, 0x30U,
0x79U, 0x90U, 0x80U, 0x94U,
0xe1U, 0x11U, 0x21U, 0xd0U,
0x42U, 0x35U, 0x4aU, 0x7cU,
0x1fU, 0x55U, 0xb6U, 0x48U,
0x2cU, 0xa1U, 0xa5U, 0x1eU,
0x1bU, 0x25U, 0x0dU, 0xfdU,
0x1eU, 0xd0U, 0xeeU, 0xf9U,
)
val actual = function.hash(
UByteArray(0)
)
assertContentEquals(expected, actual)
}
}