Skip to content

Commit

Permalink
Replace DigestDelegate with inline functions (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
05nelsonm authored Dec 19, 2024
1 parent 24a773b commit f2ae88c
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 237 deletions.
2 changes: 1 addition & 1 deletion library/digest/api/digest.api
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public abstract class org/kotlincrypto/core/digest/Digest : java/security/Messag
}

public abstract class org/kotlincrypto/core/digest/internal/DigestState {
public synthetic fun <init> (Ljava/lang/String;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;IIJLkotlin/jvm/internal/DefaultConstructorMarker;)V
}

2 changes: 1 addition & 1 deletion library/digest/api/digest.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ abstract class org.kotlincrypto.core.digest/Digest : org.kotlincrypto.core/Algor
}

sealed class org.kotlincrypto.core.digest.internal/DigestState { // org.kotlincrypto.core.digest.internal/DigestState|null[0]
constructor <init>(kotlin/String, kotlin/Int, kotlin/Int) // org.kotlincrypto.core.digest.internal/DigestState.<init>|<init>(kotlin.String;kotlin.Int;kotlin.Int){}[0]
constructor <init>(kotlin/String, kotlin/Int, kotlin/Int, kotlin/Long) // org.kotlincrypto.core.digest.internal/DigestState.<init>|<init>(kotlin.String;kotlin.Int;kotlin.Int;kotlin.Long){}[0]
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,7 @@ import org.kotlincrypto.core.digest.internal.DigestState
*
* https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms
* */
public expect abstract class Digest private constructor(
algorithm: String,
blockSize: Int,
digestLength: Int,
state: DigestState?,
) : Algorithm,
Copyable<Digest>,
Resettable,
Updatable
{
public expect abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Updatable {

/**
* Creates a new [Digest] for the specified parameters.
Expand Down Expand Up @@ -81,10 +72,6 @@ public expect abstract class Digest private constructor(

public final override fun reset()

public final override fun equals(other: Any?): Boolean
public final override fun hashCode(): Int
public final override fun toString(): String

public final override fun copy(): Digest
protected abstract fun copy(state: DigestState): Digest

Expand All @@ -109,4 +96,8 @@ public expect abstract class Digest private constructor(
* override and intercept if necessary.
* */
protected open fun updateDigest(input: ByteArray, offset: Int, len: Int)

public final override fun equals(other: Any?): Boolean
public final override fun hashCode(): Int
public final override fun toString(): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* Copyright (c) 2024 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.
**/
@file:Suppress("KotlinRedundantDiagnosticSuppress")

package org.kotlincrypto.core.digest.internal

import kotlin.jvm.JvmInline
import kotlin.jvm.JvmSynthetic

@JvmInline
internal value class Buffer private constructor(internal val value: ByteArray) {

internal fun toState(
algorithm: String,
digestLength: Int,
bufOffs: Int,
compressCount: Long,
): DigestState = State(
algorithm,
digestLength,
bufOffs,
compressCount,
this,
)

private class State(
algorithm: String,
digestLength: Int,
bufOffs: Int,
compressCount: Long,
buf: Buffer,
): DigestState(
algorithm,
digestLength,
bufOffs,
compressCount,
) {
val buf = Buffer(buf.value.copyOf())
}

internal companion object {

@JvmSynthetic
internal fun DigestState.buf(): Buffer = Buffer((this as State).buf.value.copyOf())

@JvmSynthetic
@Throws(IllegalArgumentException::class)
internal fun initialize(
algorithm: String,
blockSize: Int,
digestLength: Int,
): Buffer {
require(algorithm.isNotBlank()) { "algorithm cannot be blank" }
require(blockSize > 0) { "blockSize must be greater than 0" }
require(blockSize % 8 == 0) { "blockSize must be a factor of 8" }
require(digestLength >= 0) { "digestLength cannot be negative" }
return Buffer(ByteArray(blockSize))
}
}
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.update(
input: Byte,
bufOffsGetAndIncrement: () -> Int,
bufOffsReset: () -> Unit,
compress: (buf: ByteArray, offset: Int) -> Unit,
compressCountIncrement: () -> Unit,
) {
val bufOffs = bufOffsGetAndIncrement()
value[bufOffs] = input

// value.size == blockSize
if ((bufOffs + 1) != value.size) return
compress(value, 0)
compressCountIncrement()
bufOffsReset()
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.update(
input: ByteArray,
offset: Int,
len: Int,
bufOffsGet: () -> Int,
bufOffsGetAndIncrement: () -> Int,
bufOffsReset: () -> Unit,
compress: (buf: ByteArray, offset: Int) -> Unit,
compressCountIncrement: () -> Unit,
) {
var i = offset
var remaining = len

// Fill buffer if not already empty
while (bufOffsGet() != 0 && remaining > 0) {
update(
input[i++],
bufOffsGetAndIncrement,
bufOffsReset,
compress,
compressCountIncrement,
)
--remaining
}

// Chunk
while (remaining >= value.size) {
compress(input, i)
i += value.size
remaining -= value.size
compressCountIncrement()
}

// Add remaining to buffer
while (remaining-- > 0) {
update(
input[i++],
bufOffsGetAndIncrement,
bufOffsReset,
compress,
compressCountIncrement,
)
}
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.digest(
bufOffs: Int,
compressCount: Long,
digest: (bitLength: Long, offs: Int, buf: ByteArray) -> ByteArray,
resetBufOffs: () -> Unit,
resetCompressCount: () -> Unit,
resetDigest: () -> Unit,
): ByteArray {
val bitLength = ((compressCount * value.size) + bufOffs) * 8
val final = digest(bitLength, bufOffs, value)
reset(resetBufOffs, resetCompressCount, resetDigest)
return final
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.reset(
resetBufOffs: () -> Unit,
resetCompressCount: () -> Unit,
resetDigest: () -> Unit,
) {
value.fill(0)
resetBufOffs()
resetCompressCount()
resetDigest()
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ package org.kotlincrypto.core.digest.internal

/**
* Used as a holder for copying/cloning of digests.
*
* @see [DigestDelegate.RealState]
* */
public sealed class DigestState(
internal val algorithm: String,
internal val blockSize: Int,
internal val digestLength: Int,
internal val bufOffs: Int,
internal val compressCount: Long,
)
Loading

0 comments on commit f2ae88c

Please sign in to comment.