Skip to content

Commit f2ae88c

Browse files
authored
Replace DigestDelegate with inline functions (#66)
1 parent 24a773b commit f2ae88c

File tree

8 files changed

+313
-237
lines changed

8 files changed

+313
-237
lines changed

library/digest/api/digest.api

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ public abstract class org/kotlincrypto/core/digest/Digest : java/security/Messag
3131
}
3232

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

library/digest/api/digest.klib.api

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ abstract class org.kotlincrypto.core.digest/Digest : org.kotlincrypto.core/Algor
2929
}
3030

3131
sealed class org.kotlincrypto.core.digest.internal/DigestState { // org.kotlincrypto.core.digest.internal/DigestState|null[0]
32-
constructor <init>(kotlin/String, kotlin/Int, kotlin/Int) // org.kotlincrypto.core.digest.internal/DigestState.<init>|<init>(kotlin.String;kotlin.Int;kotlin.Int){}[0]
32+
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]
3333
}

library/digest/src/commonMain/kotlin/org/kotlincrypto/core/digest/Digest.kt

+5-14
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,7 @@ import org.kotlincrypto.core.digest.internal.DigestState
3131
*
3232
* https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms
3333
* */
34-
public expect abstract class Digest private constructor(
35-
algorithm: String,
36-
blockSize: Int,
37-
digestLength: Int,
38-
state: DigestState?,
39-
) : Algorithm,
40-
Copyable<Digest>,
41-
Resettable,
42-
Updatable
43-
{
34+
public expect abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Updatable {
4435

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

8273
public final override fun reset()
8374

84-
public final override fun equals(other: Any?): Boolean
85-
public final override fun hashCode(): Int
86-
public final override fun toString(): String
87-
8875
public final override fun copy(): Digest
8976
protected abstract fun copy(state: DigestState): Digest
9077

@@ -109,4 +96,8 @@ public expect abstract class Digest private constructor(
10996
* override and intercept if necessary.
11097
* */
11198
protected open fun updateDigest(input: ByteArray, offset: Int, len: Int)
99+
100+
public final override fun equals(other: Any?): Boolean
101+
public final override fun hashCode(): Int
102+
public final override fun toString(): String
112103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright (c) 2024 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+
@file:Suppress("KotlinRedundantDiagnosticSuppress")
17+
18+
package org.kotlincrypto.core.digest.internal
19+
20+
import kotlin.jvm.JvmInline
21+
import kotlin.jvm.JvmSynthetic
22+
23+
@JvmInline
24+
internal value class Buffer private constructor(internal val value: ByteArray) {
25+
26+
internal fun toState(
27+
algorithm: String,
28+
digestLength: Int,
29+
bufOffs: Int,
30+
compressCount: Long,
31+
): DigestState = State(
32+
algorithm,
33+
digestLength,
34+
bufOffs,
35+
compressCount,
36+
this,
37+
)
38+
39+
private class State(
40+
algorithm: String,
41+
digestLength: Int,
42+
bufOffs: Int,
43+
compressCount: Long,
44+
buf: Buffer,
45+
): DigestState(
46+
algorithm,
47+
digestLength,
48+
bufOffs,
49+
compressCount,
50+
) {
51+
val buf = Buffer(buf.value.copyOf())
52+
}
53+
54+
internal companion object {
55+
56+
@JvmSynthetic
57+
internal fun DigestState.buf(): Buffer = Buffer((this as State).buf.value.copyOf())
58+
59+
@JvmSynthetic
60+
@Throws(IllegalArgumentException::class)
61+
internal fun initialize(
62+
algorithm: String,
63+
blockSize: Int,
64+
digestLength: Int,
65+
): Buffer {
66+
require(algorithm.isNotBlank()) { "algorithm cannot be blank" }
67+
require(blockSize > 0) { "blockSize must be greater than 0" }
68+
require(blockSize % 8 == 0) { "blockSize must be a factor of 8" }
69+
require(digestLength >= 0) { "digestLength cannot be negative" }
70+
return Buffer(ByteArray(blockSize))
71+
}
72+
}
73+
}
74+
75+
@Suppress("NOTHING_TO_INLINE")
76+
internal inline fun Buffer.update(
77+
input: Byte,
78+
bufOffsGetAndIncrement: () -> Int,
79+
bufOffsReset: () -> Unit,
80+
compress: (buf: ByteArray, offset: Int) -> Unit,
81+
compressCountIncrement: () -> Unit,
82+
) {
83+
val bufOffs = bufOffsGetAndIncrement()
84+
value[bufOffs] = input
85+
86+
// value.size == blockSize
87+
if ((bufOffs + 1) != value.size) return
88+
compress(value, 0)
89+
compressCountIncrement()
90+
bufOffsReset()
91+
}
92+
93+
@Suppress("NOTHING_TO_INLINE")
94+
internal inline fun Buffer.update(
95+
input: ByteArray,
96+
offset: Int,
97+
len: Int,
98+
bufOffsGet: () -> Int,
99+
bufOffsGetAndIncrement: () -> Int,
100+
bufOffsReset: () -> Unit,
101+
compress: (buf: ByteArray, offset: Int) -> Unit,
102+
compressCountIncrement: () -> Unit,
103+
) {
104+
var i = offset
105+
var remaining = len
106+
107+
// Fill buffer if not already empty
108+
while (bufOffsGet() != 0 && remaining > 0) {
109+
update(
110+
input[i++],
111+
bufOffsGetAndIncrement,
112+
bufOffsReset,
113+
compress,
114+
compressCountIncrement,
115+
)
116+
--remaining
117+
}
118+
119+
// Chunk
120+
while (remaining >= value.size) {
121+
compress(input, i)
122+
i += value.size
123+
remaining -= value.size
124+
compressCountIncrement()
125+
}
126+
127+
// Add remaining to buffer
128+
while (remaining-- > 0) {
129+
update(
130+
input[i++],
131+
bufOffsGetAndIncrement,
132+
bufOffsReset,
133+
compress,
134+
compressCountIncrement,
135+
)
136+
}
137+
}
138+
139+
@Suppress("NOTHING_TO_INLINE")
140+
internal inline fun Buffer.digest(
141+
bufOffs: Int,
142+
compressCount: Long,
143+
digest: (bitLength: Long, offs: Int, buf: ByteArray) -> ByteArray,
144+
resetBufOffs: () -> Unit,
145+
resetCompressCount: () -> Unit,
146+
resetDigest: () -> Unit,
147+
): ByteArray {
148+
val bitLength = ((compressCount * value.size) + bufOffs) * 8
149+
val final = digest(bitLength, bufOffs, value)
150+
reset(resetBufOffs, resetCompressCount, resetDigest)
151+
return final
152+
}
153+
154+
@Suppress("NOTHING_TO_INLINE")
155+
internal inline fun Buffer.reset(
156+
resetBufOffs: () -> Unit,
157+
resetCompressCount: () -> Unit,
158+
resetDigest: () -> Unit,
159+
) {
160+
value.fill(0)
161+
resetBufOffs()
162+
resetCompressCount()
163+
resetDigest()
164+
}

library/digest/src/commonMain/kotlin/org/kotlincrypto/core/digest/internal/DigestDelegate.kt

-140
This file was deleted.

library/digest/src/commonMain/kotlin/org/kotlincrypto/core/digest/internal/DigestState.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ package org.kotlincrypto.core.digest.internal
1717

1818
/**
1919
* Used as a holder for copying/cloning of digests.
20-
*
21-
* @see [DigestDelegate.RealState]
2220
* */
2321
public sealed class DigestState(
2422
internal val algorithm: String,
25-
internal val blockSize: Int,
2623
internal val digestLength: Int,
24+
internal val bufOffs: Int,
25+
internal val compressCount: Long,
2726
)

0 commit comments

Comments
 (0)