refactor, implement LCG

LCG ... Linear Congruential Generator
This commit is contained in:
2025-11-10 18:52:19 +01:00
parent 7db8972e27
commit feecfa49b9
7 changed files with 109 additions and 69 deletions

View File

@@ -25,6 +25,10 @@ kotlin {
implementation(libs.bytearray)
}
}
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalUnsignedTypes")
}
}
publishing {

View File

@@ -1,8 +1,8 @@
[versions]
kotlin = "2.1.20"
hash = "1.2.2"
mac = "1.1.2"
bytearray = "1.1.1"
hash = "1.3.2"
mac = "1.2.0"
bytearray = "1.2.2"
[plugins]
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.hash.HashFunction
import kotlin.random.Random
abstract class PRNG : Random() {
abstract fun seed(
seed: ByteArray,
)
abstract fun reseed(
entropy: ByteArray,
seed: UByteArray,
)
abstract fun generate(
count: Int,
): ByteArray
): UByteArray
override fun nextBits(
bitCount: Int,
@@ -27,10 +22,6 @@ abstract class PRNG : Random() {
}
companion object {
fun HMAC(
function: HashFunction,
): HMAC {
return com.infendro.random.HMAC(function)
}
fun LCG() = com.infendro.random.prng.LCG()
}
}