Compare commits

...

2 Commits

Author SHA1 Message Date
a8a8ea940c bump version to 1.2.0
All checks were successful
/ publish (push) Successful in 2m35s
2025-11-10 18:52:59 +01:00
feecfa49b9 refactor, implement LCG
LCG ... Linear Congruential Generator
2025-11-10 18:52:19 +01:00
7 changed files with 110 additions and 70 deletions

View File

@@ -1,5 +1,5 @@
group = "com.infendro" group = "com.infendro"
version = "1.1.0" version = "1.2.0"
repositories { repositories {
maven("https://git.infendro.com/api/packages/Infendro/maven") maven("https://git.infendro.com/api/packages/Infendro/maven")
@@ -25,6 +25,10 @@ kotlin {
implementation(libs.bytearray) implementation(libs.bytearray)
} }
} }
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalUnsignedTypes")
}
} }
publishing { publishing {

View File

@@ -1,8 +1,8 @@
[versions] [versions]
kotlin = "2.1.20" kotlin = "2.1.20"
hash = "1.2.2" hash = "1.3.2"
mac = "1.1.2" mac = "1.2.0"
bytearray = "1.1.1" bytearray = "1.2.2"
[plugins] [plugins]
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }

View File

@@ -1,53 +0,0 @@
package com.infendro.random
import com.infendro.bytearray.addAll
import com.infendro.hash.HashFunction
class HMAC internal constructor(
private val function: HashFunction,
) : PRNG() {
private val random = Default
private val hmac = com.infendro.mac.HMAC(function)
private lateinit var K: ByteArray
private lateinit var V: ByteArray
init {
val bytes = random.nextBytes(function.bytes)
seed(bytes)
}
override fun seed(
seed: ByteArray,
) {
K = ByteArray(function.bytes) { 0x00 }
V = ByteArray(function.bytes) { 0x01 }
reseed(seed)
}
override fun reseed(
entropy: ByteArray,
) {
K = hmac.hash(K, V + byteArrayOf(0x00) + entropy)
V = hmac.hash(K, V)
K = hmac.hash(K, V + byteArrayOf(0x01) + entropy)
V = hmac.hash(K, V)
}
override fun generate(
count: Int,
): ByteArray {
val bytes = buildList {
while (size < count) {
V = hmac.hash(K, V)
addAll(V)
}
}
K = hmac.hash(K, V + byteArrayOf(0x00))
V = hmac.hash(K, V)
return bytes
.take(count)
.toByteArray()
}
}

View File

@@ -0,0 +1,16 @@
package com.infendro.random.csprng
import com.infendro.hash.HashFunction
import com.infendro.random.prng.PRNG
abstract class CSPRNG : PRNG() {
abstract fun reseed(
entropy: UByteArray,
)
companion object {
fun HMAC(
function: HashFunction,
) = com.infendro.random.csprng.HMAC(function)
}
}

View File

@@ -0,0 +1,48 @@
package com.infendro.random.csprng
import com.infendro.hash.HashFunction
import kotlin.math.min
import kotlin.properties.Delegates.notNull
class HMAC internal constructor(
private val function: HashFunction,
) : CSPRNG() {
private val hmac = com.infendro.mac.HMAC(function)
private var k: UByteArray by notNull()
private var v: UByteArray by notNull()
override fun seed(
seed: UByteArray,
) {
k = UByteArray(function.bytes) { 0x00U }
v = UByteArray(function.bytes) { 0x01U }
reseed(seed)
}
override fun reseed(
entropy: UByteArray,
) {
k = hmac.hash(k, v + ubyteArrayOf(0x00U) + entropy)
v = hmac.hash(k, v)
k = hmac.hash(k, v + ubyteArrayOf(0x01U) + entropy)
v = hmac.hash(k, v)
}
override fun generate(
count: Int,
): UByteArray {
val bytes = buildList {
while (size < count) {
v = hmac.hash(k, v)
addAll(v.take(min(count - size, function.bytes)))
}
}.toUByteArray()
k = hmac.hash(k, v + ubyteArrayOf(0x00U))
v = hmac.hash(k, v)
return bytes
}
}

View File

@@ -0,0 +1,34 @@
package com.infendro.random.prng
import com.infendro.bytearray.padStart
import com.infendro.bytearray.toUByteArray
import com.infendro.bytearray.toULong
import kotlin.math.min
import kotlin.properties.Delegates
class LCG internal constructor() : PRNG() {
private val a: ULong = 25214903917UL
private val c: ULong = 11UL
private val m: ULong = 1UL shl 48
private var x: ULong by Delegates.notNull()
override fun seed(
seed: UByteArray,
) {
val s = seed.padStart(8, 0x00U).takeLast(8).toUByteArray()
x = s.toULong() % m
}
override fun generate(
count: Int,
): UByteArray {
return buildList {
while (size < count) {
x = (a * x + c) % m
addAll(x.toUByteArray().takeLast(min(count - size, 6)))
}
}.toUByteArray()
}
}

View File

@@ -1,21 +1,16 @@
package com.infendro.random package com.infendro.random.prng
import com.infendro.bytearray.toInt import com.infendro.bytearray.toInt
import com.infendro.hash.HashFunction
import kotlin.random.Random import kotlin.random.Random
abstract class PRNG : Random() { abstract class PRNG : Random() {
abstract fun seed( abstract fun seed(
seed: ByteArray, seed: UByteArray,
)
abstract fun reseed(
entropy: ByteArray,
) )
abstract fun generate( abstract fun generate(
count: Int, count: Int,
): ByteArray ): UByteArray
override fun nextBits( override fun nextBits(
bitCount: Int, bitCount: Int,
@@ -27,10 +22,6 @@ abstract class PRNG : Random() {
} }
companion object { companion object {
fun HMAC( fun LCG() = com.infendro.random.prng.LCG()
function: HashFunction,
): HMAC {
return com.infendro.random.HMAC(function)
}
} }
} }