From 37158a83dcd07df36e1fc2d6df06208ad1093ca7 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 20 Dec 2025 12:26:16 -0500 Subject: [PATCH] Adds a nextLong random method Adds unbounded methods because they are faster. --- .../quartz/utils/RandomInstance.kt | 8 ++- .../quartz/utils/SecureRandom.kt | 6 +++ .../quartz/utils/SecureRandom.ios.kt | 50 ++++++++++++++++--- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt index 557c0b383..295854a14 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt @@ -23,7 +23,13 @@ package com.vitorpamplona.quartz.utils object RandomInstance { val randomizer = SecureRandom() - fun int(bound: Int = Int.MAX_VALUE) = randomizer.nextInt(bound) + fun int() = randomizer.nextInt() + + fun long() = randomizer.nextLong() + + fun int(bound: Int) = randomizer.nextInt(bound) + + fun long(bound: Long) = randomizer.nextLong(bound) fun bytes(size: Int) = ByteArray(size).also { randomizer.nextBytes(it) } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt index e9b7097cf..c1cb21d5d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt @@ -23,5 +23,11 @@ package com.vitorpamplona.quartz.utils expect class SecureRandom() { fun nextInt(bound: Int): Int + fun nextLong(bound: Long): Long + + fun nextInt(): Int + + fun nextLong(): Long + fun nextBytes(output: ByteArray) } diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt index 5029a922e..26f0ed41d 100644 --- a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt @@ -24,8 +24,18 @@ import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.refTo import platform.Security.SecRandomCopyBytes import platform.Security.kSecRandomDefault +import kotlin.random.Random.Default.nextBytes actual class SecureRandom { + actual fun nextInt(): Int { + val bytes = ByteArray(4) + nextBytes(bytes) + return ((bytes[0].toInt() and 0xFF) shl 24) or + ((bytes[1].toInt() and 0xFF) shl 16) or + ((bytes[2].toInt() and 0xFF) shl 8) or + (bytes[3].toInt() and 0xFF) + } + actual fun nextInt(bound: Int): Int { require(bound > 0) { throw IllegalArgumentException("Bad Bound $bound") } @@ -47,14 +57,40 @@ actual class SecureRandom { return intValue } - fun nextPositiveInt(): Int { - val bytes = ByteArray(4) + actual fun nextLong(): Long { + val bytes = ByteArray(8) nextBytes(bytes) - val value = - ((bytes[0].toInt() and 0xFF) shl 24) or - ((bytes[1].toInt() and 0xFF) shl 16) or - ((bytes[2].toInt() and 0xFF) shl 8) or - (bytes[3].toInt() and 0xFF) + return ((bytes[0].toLong() and 0xFFL) shl 56) or + ((bytes[1].toLong() and 0xFFL) shl 48) or + ((bytes[2].toLong() and 0xFFL) shl 40) or + ((bytes[3].toLong() and 0xFFL) shl 32) or + ((bytes[4].toLong() and 0xFFL) shl 24) or + ((bytes[5].toLong() and 0xFFL) shl 16) or + ((bytes[6].toLong() and 0xFFL) shl 8) or + (bytes[7].toLong() and 0xFFL) + } + + actual fun nextLong(bound: Long): Long { + require(bound > 0) { throw IllegalArgumentException("Bad Bound $bound") } + + if (bound < Int.MAX_VALUE) { + return nextInt(bound.toInt()).toLong() + } + + return nextPositiveLong() % bound + } + + fun nextPositiveInt(): Int { + val value = nextInt() + return if (value > 0) { + value + } else { + -value + } + } + + fun nextPositiveLong(): Long { + val value = nextLong() return if (value > 0) { value } else {