Skip to content

Add Dokka docs at https://core.kotlincrypto.org #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ build/
*.iml
.idea/
local.properties
.kotlin/

gh-pages/*
!gh-pages/publish.sh
193 changes: 3 additions & 190 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ Low level core cryptographic components for Kotlin Multiplatform
NOTE: For Jvm, `Digest` extends `java.security.MessageDigest` and `Mac` extends `javax.crypto.Mac`
for interoperability.

Utilized by [KotlinCrypto/hash][url-hash] and [KotlinCrypto/MACs][url-macs]

### Library Authors

Modules in `core` are intentionally **single purpose** and **small** such that you
Expand All @@ -50,190 +48,9 @@ class FooFeatureA(digest: Digest) {

### Usage

<details>
<summary>Digest</summary>

```kotlin
// Using SHA256 from hash repo as an example
import org.kotlincrypto.hash.sha2.SHA256

fun main() {
val digest = SHA256()
val bytes = Random.Default.nextBytes(615)

// Digest implements Algorithm
println(digest.algorithm())

// Digest implements Updatable
digest.update(5.toByte())
digest.update(bytes)
digest.update(bytes, 10, 88)

// Digest implements Resettable
digest.reset()

digest.update(bytes)

// Digest implements Copyable
val copy = digest.copy()

val hash = digest.digest()
val hash2 = copy.digest(bytes)
}
```

</details>

<details>
<summary>Mac</summary>

```kotlin
// Using SecureRandom from the secure-random repo as an example
import org.kotlincrypto.SecureRandom
// Using HmacSHA3_256 from the MACs repo as an example
import org.kotlincrypto.macs.hmac.sha3.HmacSHA3_256

fun main() {
val key = SecureRandom().nextBytesOf(100)
val mac = HmacSHA3_256(key)
val bytes = Random.Default.nextBytes(615)

// Mac implements Algorithm
println(mac.algorithm())

// Mac implements Updatable
mac.update(5.toByte())
mac.update(bytes)
mac.update(bytes, 10, 88)

// Mac implements Resettable
mac.reset()

mac.update(bytes)

// Mac implements Copyable
val copy = mac.copy()

val hash = mac.doFinal()
val hash2 = copy.doFinal(bytes)

// Reinitialize Mac instance with a new key
// to use for something else.
val newKey = SecureRandom().nextBytesOf(100)
mac.reset(newKey = newKey)

// Zero out key material before dereferencing
copy.clearKey()
}
```

</details>

<details>
<summary>Xof</summary>

`XOF`s (i.e. [Extendable-Output Functions][url-pub-xof]) were introduced with `SHA3`.

`XOF`s are very similar to `Digest` and `Mac` except that instead of calling `digest()`
or `doFinal()`, which returns a fixed size `ByteArray`, their output size can be variable
in length.

As such, [KotlinCrypto][url-kotlin-crypto] takes the approach of making them distinctly
different from those types, while implementing the same interfaces (`Algorithm`, `Copyable`,
`Resettable`, `Updatable`).

Output for an `Xof` is done by reading, instead.

```kotlin
// Using SHAKE128 from hash repo as an example
import org.kotlincrypto.hash.sha3.SHAKE128

fun main() {
val xof: Xof<SHAKE128> = SHAKE128.xOf()
val bytes = Random.Default.nextBytes(615)

// Xof implements Algorithm
println(xof.algorithm())

// Xof implements Updatable
xof.update(5.toByte())
xof.update(bytes)
xof.update(bytes, 10, 88)

// Xof implements Resettable
xof.reset()

xof.update(bytes)

// Xof implements Copyable
xof.copy()

val out1 = ByteArray(100)
val out2 = ByteArray(12345)

// Use produces a Reader which auto-closes when your action finishes.
// Reader is using a snapshot of the Xof state (thus the
// optional argument to resetXof with a default of true).
xof.use(resetXof = false) { read(out1, 0, out1.size); read(out2) }

val out3 = ByteArray(out1.size)
val out4 = ByteArray(out2.size)

// Can also create a Reader that won't auto-close
val reader = xof.reader(resetXof = false)
reader.read(out3)
reader.read(out4)
reader.close()

try {
// The Reader has been closed and will throw
// exception when trying to read from again.
reader.use { read(out4) }
} catch (e: IllegalStateException) {
e.printStackTrace()
}

// Contents are the same because Reader uses
// a snapshot of Xof, which was not updated
// between production of Readers.
assertContentEquals(out1 + out2, out3 + out4)

// Still able to update Xof, independent of the production
// and usage of Readers.
xof.update(10.toByte())
xof.use { read(out3); read(out4) }

try {
assertContentEquals(out1 + out2, out3 + out4)
throw IllegalStateException()
} catch (_: AssertionError) {
// pass
}
}
```

```kotlin
// Using KMAC128 from MACs repo as an example
import org.kotlincrypto.macs.kmac.KMAC128
// Using SecureRandom from the secure-random repo as an example
import org.kotlincrypto.SecureRandom

fun main() {
val key = SecureRandom().nextBytesOf(100)
val kmacXof: Xof<KMAC128> = KMAC128.xOf(key)

// If Xof is for a Mac that implements ReKeyableXofAlgorithm,
// reinitialize the instance via the `Xof.Companion.reset`
// extension function for reuse.
val newKey = SecureRandom().nextBytesOf(100)
kmacXof.reset(newKey = newKey)

// Or zero out key material before dereferencing
kmacXof.reset(newKey = ByteArray(1))
}
```

</details>
- See module [digest](library/digest/README.md)
- See module [mac](library/mac/README.md)
- See module [xof](library/xof/README.md)

### Get Started

Expand Down Expand Up @@ -280,8 +97,4 @@ dependencies {
[url-latest-release]: https://github.com/KotlinCrypto/core/releases/latest
[url-license]: https://www.apache.org/licenses/LICENSE-2.0.txt
[url-kotlin]: https://kotlinlang.org
[url-kotlin-crypto]: https://github.com/KotlinCrypto
[url-hash]: https://github.com/KotlinCrypto/hash
[url-macs]: https://github.com/KotlinCrypto/MACs
[url-version-catalog]: https://github.com/KotlinCrypto/version-catalog
[url-pub-xof]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
1 change: 1 addition & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ plugins {
}

dependencies {
implementation(libs.gradle.dokka)
implementation(libs.gradle.kmp.configuration)
implementation(libs.gradle.kotlin)
implementation(libs.gradle.publish.maven)
Expand Down
2 changes: 1 addition & 1 deletion build-logic/src/main/kotlin/-KmpConfigurationExtension.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fun KmpConfigurationExtension.configureShared(
mingwAll()

common {
if (publish) pluginIds("publication")
if (publish) pluginIds("publication", "dokka")

sourceSetTest {
dependencies {
Expand Down
42 changes: 42 additions & 0 deletions build-logic/src/main/kotlin/dokka.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2025 Matthew Nelson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
import org.jetbrains.dokka.DokkaConfiguration.Visibility
import org.jetbrains.dokka.gradle.DokkaTaskPartial
import java.net.URI

plugins {
id("org.jetbrains.dokka")
}

tasks.withType<DokkaTaskPartial>().configureEach {
suppressInheritedMembers = true

dokkaSourceSets.configureEach {
includes.from("README.md")
noStdlibLink = true

sourceLink {
localDirectory = rootDir
remoteUrl = URI("https://github.com/KotlinCrypto/core/tree/master").toURL()
remoteLineSuffix = "#L"
}

documentedVisibilities.set(setOf(
Visibility.PUBLIC,
Visibility.PROTECTED,
))
}
}
5 changes: 2 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ plugins {
alias(libs.plugins.android.library) apply(false)
alias(libs.plugins.benchmark) apply(false)
alias(libs.plugins.binary.compat)
alias(libs.plugins.dokka)
alias(libs.plugins.kotlin.multiplatform) apply(false)
}

Expand All @@ -29,9 +30,7 @@ allprojects {
findProperty("VERSION_NAME")?.let { version = it }
findProperty("POM_DESCRIPTION")?.let { description = it.toString() }

repositories {
mavenCentral()
}
repositories { mavenCentral() }
}

@Suppress("PropertyName")
Expand Down
36 changes: 36 additions & 0 deletions gh-pages/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (c) 2025 Matthew Nelson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e

readonly DIR_SCRIPT="$( cd "$( dirname "$0" )" >/dev/null && pwd )"
readonly REPO_NAME="core"

trap 'rm -rf "$DIR_SCRIPT/$REPO_NAME"' EXIT

cd "$DIR_SCRIPT"
git clone -b gh-pages --single-branch https://github.com/KotlinCrypto/$REPO_NAME.git
rm -rf "$DIR_SCRIPT/$REPO_NAME/"*
echo "$REPO_NAME.kotlincrypto.org" > "$DIR_SCRIPT/$REPO_NAME/CNAME"

cd ..
./gradlew clean -DKMP_TARGETS_ALL
./gradlew dokkaHtmlMultiModule --no-build-cache -DKMP_TARGETS_ALL
cp -aR build/dokka/htmlMultiModule/* gh-pages/$REPO_NAME

cd "$DIR_SCRIPT/$REPO_NAME"
sed -i "s|module:|module:library/|g" "package-list"

git add --all
git commit -S --message "Update dokka docs"
git push
35 changes: 19 additions & 16 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
[versions]
androidx-test-runner = "1.5.2"
androidx-test-runner = "1.5.2"

gradle-benchmark = "0.4.11"
gradle-android = "8.2.2"
gradle-binary-compat = "0.16.3"
gradle-kmp-configuration = "0.3.2"
gradle-kotlin = "1.9.24"
gradle-publish-maven = "0.29.0"
gradle-benchmark = "0.4.11"
gradle-android = "8.2.2"
gradle-binary-compat = "0.16.3"
gradle-dokka = "1.9.20"
gradle-kmp-configuration = "0.3.2"
gradle-kotlin = "1.9.24"
gradle-publish-maven = "0.29.0"

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

# tests & tools
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" }
benchmark-runtime = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "gradle-benchmark" }
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" }
benchmark-runtime = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "gradle-benchmark" }

[plugins]
android-library = { id = "com.android.library", version.ref = "gradle-android" }
benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "gradle-benchmark" }
binary-compat = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "gradle-binary-compat" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "gradle-kotlin" }
android-library = { id = "com.android.library", version.ref = "gradle-android" }
benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "gradle-benchmark" }
binary-compat = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "gradle-binary-compat" }
dokka = { id = "org.jetbrains.dokka", version.ref = "gradle-dokka" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "gradle-kotlin" }
3 changes: 3 additions & 0 deletions library/core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Module core

Very small module, only containing public interfaces and exceptions. Is exported by all other modules.
Loading
Loading