Skip to content

Commit deb36e5

Browse files
authored
Add CryptoRand implementation (#28)
1 parent fd4c618 commit deb36e5

53 files changed

Lines changed: 981 additions & 1175 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[![badge-latest-release]][url-latest-release]
44

55
[![badge-kotlin]][url-kotlin]
6+
[![badge-error]][url-error]
67

78
![badge-platform-android]
89
![badge-platform-jvm]
@@ -96,6 +97,7 @@ dependencies {
9697

9798
<!-- TAG_DEPENDENCIES -->
9899
[badge-kotlin]: https://img.shields.io/badge/kotlin-1.9.24-blue.svg?logo=kotlin
100+
[badge-error]: https://img.shields.io/badge/kotlincrypto.error-0.2.0-blue.svg
99101

100102
<!-- TAG_PLATFORMS -->
101103
[badge-platform-android]: http://img.shields.io/badge/-android-6EDB8D.svg?style=flat
@@ -119,3 +121,4 @@ dependencies {
119121
[url-kotlin]: https://kotlinlang.org
120122
[url-rust-random]: https://github.com/rust-random/getrandom
121123
[url-version-catalog]: https://github.com/KotlinCrypto/version-catalog
124+
[url-error]: https://github.com/KotlinCrypto/error

benchmarks/README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# benchmarks
22

3-
<!-- TODO: CryptoRand Issue #23 -->
4-
Benchmarks for tracking performance of `SecureRandom` implementation.
3+
Benchmarks for tracking performance of `CryptoRand` implementation.
54

65
**NOTE:** Benchmarking is run on every Pull Request. Results can be viewed for each
76
workflow run on the [GitHub Actions][url-actions] tab of the repository.
@@ -31,5 +30,4 @@ workflow run on the [GitHub Actions][url-actions] tab of the repository.
3130
./gradlew nativeHostBenchmark
3231
```
3332

34-
<!-- TODO: CryptoRand Issue #23 -->
35-
[url-actions]: https://github.com/KotlinCrypto/secure-random/actions/
33+
[url-actions]: https://github.com/KotlinCrypto/crypto-rand/actions/

benchmarks/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ kmpConfiguration {
5454
sourceSetMain {
5555
dependencies {
5656
implementation(libs.benchmark.runtime)
57-
implementation(project(":library:secure-random"))
57+
implementation(project(":library:crypto-rand"))
5858
}
5959
}
6060
}

benchmarks/src/commonMain/kotlin/org/kotlincrypto/benchmarks/SecureRandomBenchmark.kt renamed to benchmarks/src/commonMain/kotlin/org/kotlincrypto/benchmarks/CryptoRandBenchmark.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,24 @@
1818
package org.kotlincrypto.benchmarks
1919

2020
import kotlinx.benchmark.*
21-
import org.kotlincrypto.SecureRandom
21+
import org.kotlincrypto.crypto.rand.CryptoRand
2222

2323
@State(Scope.Benchmark)
2424
@BenchmarkMode(Mode.AverageTime)
2525
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
2626
@Warmup(iterations = 5, time = 2)
2727
@Measurement(iterations = 5, time = 3)
28-
open class SecureRandomBenchmark {
28+
open class CryptoRandBenchmark {
2929

3030
private val buf = ByteArray(20)
3131

3232
@Setup
3333
fun setup() {
34-
SECURE_RANDOM.nextBytesCopyTo(buf)
34+
CryptoRand.Default.nextBytes(buf)
3535
}
3636

3737
@Benchmark
38-
fun nextBytesCopyTo() {
39-
SECURE_RANDOM.nextBytesCopyTo(buf)
40-
}
41-
42-
private companion object {
43-
private val SECURE_RANDOM = SecureRandom()
38+
fun nextBytes() {
39+
CryptoRand.Default.nextBytes(buf)
4440
}
4541
}

gradle/libs.versions.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ gradle-kmp-configuration = "0.3.2"
55
gradle-kotlin = "1.9.24"
66
gradle-publish-maven = "0.29.0"
77

8-
kotlinx-coroutines = "1.8.1"
8+
kotlincrypto-error = "0.2.0"
99

1010
[libraries]
1111
gradle-kmp-configuration = { module = "io.matthewnelson:gradle-kmp-configuration-plugin", version.ref = "gradle-kmp-configuration" }
1212
gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "gradle-kotlin" }
1313
gradle-publish-maven = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "gradle-publish-maven" }
1414

15+
kotlincrypto-error = { module = "org.kotlincrypto:error", version.ref = "kotlincrypto-error" }
16+
1517
# tests
1618
benchmark-runtime = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "gradle-benchmark" }
17-
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
1819

1920
[plugins]
2021
benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "gradle-benchmark" }

library/crypto-rand/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
public abstract class org/kotlincrypto/crypto/rand/CryptoRand {
2+
public static final field Default Lorg/kotlincrypto/crypto/rand/CryptoRand$Default;
3+
protected fun <init> ()V
4+
public abstract fun nextBytes ([B)[B
5+
}
6+
7+
public final class org/kotlincrypto/crypto/rand/CryptoRand$Default : org/kotlincrypto/crypto/rand/CryptoRand {
8+
public fun nextBytes ([B)[B
9+
}
10+
11+
public abstract interface annotation class org/kotlincrypto/crypto/rand/DelicateCryptoRandApi : java/lang/annotation/Annotation {
12+
}
13+
14+
public final class org/kotlincrypto/crypto/rand/RNGException : java/security/GeneralSecurityException {
15+
public fun <init> ()V
16+
public fun <init> (Ljava/lang/String;)V
17+
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
18+
public fun <init> (Ljava/lang/Throwable;)V
19+
}
20+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Klib ABI Dump
2+
// Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, wasmWasi, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
3+
// Rendering settings:
4+
// - Signature version: 2
5+
// - Show manifest properties: true
6+
// - Show declarations: true
7+
8+
// Library unique name: <org.kotlincrypto:crypto-rand>
9+
open annotation class org.kotlincrypto.crypto.rand/DelicateCryptoRandApi : kotlin/Annotation { // org.kotlincrypto.crypto.rand/DelicateCryptoRandApi|null[0]
10+
constructor <init>() // org.kotlincrypto.crypto.rand/DelicateCryptoRandApi.<init>|<init>(){}[0]
11+
}
12+
13+
abstract class org.kotlincrypto.crypto.rand/CryptoRand { // org.kotlincrypto.crypto.rand/CryptoRand|null[0]
14+
constructor <init>() // org.kotlincrypto.crypto.rand/CryptoRand.<init>|<init>(){}[0]
15+
16+
abstract fun nextBytes(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.crypto.rand/CryptoRand.nextBytes|nextBytes(kotlin.ByteArray){}[0]
17+
18+
final object Default : org.kotlincrypto.crypto.rand/CryptoRand { // org.kotlincrypto.crypto.rand/CryptoRand.Default|null[0]
19+
final fun nextBytes(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.crypto.rand/CryptoRand.Default.nextBytes|nextBytes(kotlin.ByteArray){}[0]
20+
}
21+
}
22+
23+
final class org.kotlincrypto.crypto.rand/RNGException : org.kotlincrypto.error/GeneralSecurityException { // org.kotlincrypto.crypto.rand/RNGException|null[0]
24+
constructor <init>() // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(){}[0]
25+
constructor <init>(kotlin/String?) // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(kotlin.String?){}[0]
26+
constructor <init>(kotlin/String?, kotlin/Throwable?) // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(kotlin.String?;kotlin.Throwable?){}[0]
27+
constructor <init>(kotlin/Throwable?) // org.kotlincrypto.crypto.rand/RNGException.<init>|<init>(kotlin.Throwable?){}[0]
28+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2025 Matthew Nelson
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
plugins {
17+
id("configuration")
18+
}
19+
20+
kmpConfiguration {
21+
configureShared(java9ModuleName = "org.kotlincrypto.crypto.rand", publish = true) {
22+
common {
23+
sourceSetMain {
24+
dependencies {
25+
api(libs.kotlincrypto.error)
26+
}
27+
}
28+
}
29+
30+
kotlin {
31+
with(sourceSets) {
32+
val linuxMain = findByName("linuxMain")
33+
val androidNativeMain = findByName("androidNativeMain")
34+
35+
if (linuxMain != null || androidNativeMain != null) {
36+
val linuxAndroidMain = maybeCreate("linuxAndroidMain").apply {
37+
dependsOn(getByName("unixMain"))
38+
}
39+
val linuxAndroidTest = maybeCreate("linuxAndroidTest").apply {
40+
dependsOn(getByName("unixTest"))
41+
}
42+
43+
linuxMain?.apply { dependsOn(linuxAndroidMain) }
44+
findByName("linuxTest")?.apply { dependsOn(linuxAndroidTest) }
45+
46+
androidNativeMain?.apply { dependsOn(linuxAndroidMain) }
47+
findByName("androidNativeTest")?.apply { dependsOn(linuxAndroidTest) }
48+
}
49+
}
50+
}
51+
52+
kotlin {
53+
with(sourceSets) {
54+
val jsMain = findByName("jsMain")
55+
val wasmJsMain = findByName("wasmJsMain")
56+
57+
if (jsMain != null || wasmJsMain != null) {
58+
val jsWasmJsMain = maybeCreate("jsWasmJsMain").apply {
59+
dependsOn(getByName("nonJvmMain"))
60+
}
61+
val jsWasmJsTest = maybeCreate("jsWasmJsTest").apply {
62+
dependsOn(getByName("nonJvmTest"))
63+
}
64+
65+
jsMain?.apply { dependsOn(jsWasmJsMain) }
66+
findByName("linuxTest")?.apply { dependsOn(jsWasmJsTest) }
67+
68+
wasmJsMain?.apply { dependsOn(jsWasmJsMain) }
69+
findByName("androidNativeTest")?.apply { dependsOn(jsWasmJsTest) }
70+
}
71+
}
72+
}
73+
}
74+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright (c) 2023 Matthew Nelson
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
POM_ARTIFACT_ID=crypto-rand
15+
POM_NAME=KotlinCrypto CryptoRand
16+
POM_DESCRIPTION=KotlinCrypto library for obtaining cryptographically secure random data from the system

0 commit comments

Comments
 (0)