Skip to content
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

Inline Digest and Xof.Utils functions #98

Merged
merged 4 commits into from
Jan 11, 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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("unused")

package org.kotlincrypto.core.benchmarks

import kotlinx.benchmark.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("unused")

package org.kotlincrypto.core.benchmarks

import kotlinx.benchmark.*
import org.kotlincrypto.core.InternalKotlinCryptoApi
import org.kotlincrypto.core.xof.Xof
import kotlin.random.Random

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
Expand All @@ -28,18 +29,18 @@ import kotlin.random.Random
@OptIn(InternalKotlinCryptoApi::class)
open class XofUtilsBenchmark {

private val longs: LongArray = LongArray(10) { Random.Default.nextLong() }
private val loHi = Array(longs.size) { longs[it].let { l -> l.toInt() to l.rotateLeft(32).toInt() } }
@Benchmark
fun leftEncodeLong() {
Xof.Utils.leftEncode(-99993873488683833L)
}

@Benchmark
fun leftEncodeLongs() {
val longs = longs
longs.forEach { long -> Xof.Utils.leftEncode(long) }
fun leftEncodeInt() {
Xof.Utils.leftEncode( 11978435)
}

@Benchmark
fun leftEncodeLoHi() {
val loHi = loHi
loHi.forEach { Xof.Utils.leftEncode(it.first, it.second) }
Xof.Utils.leftEncode(184581845, 11978435)
}
}
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ POM_DEVELOPER_ID=KotlinCrypto
POM_DEVELOPER_NAME=Kotlin Crypto
POM_DEVELOPER_URL=https://github.com/KotlinCrypto/

VERSION_NAME=1.0.0-alpha01-SNAPSHOT
VERSION_NAME=0.6.0-SNAPSHOT
# 0.1.0-alpha01 = 00 01 00 11
# 0.1.0-beta01 = 00 01 00 21
# 0.1.0-rc01 = 00 01 00 31
# 0.1.0 = 00 01 00 99
# 1.1.0 = 01 01 00 99
VERSION_CODE=01000011
VERSION_CODE=00060011
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("KotlinRedundantDiagnosticSuppress")
@file:Suppress("KotlinRedundantDiagnosticSuppress", "NOTHING_TO_INLINE")

package org.kotlincrypto.core.digest.internal

import org.kotlincrypto.core.digest.Digest
import kotlin.jvm.JvmInline
import kotlin.jvm.JvmSynthetic

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

internal fun copy(): Buffer = Buffer(value.copyOf())

internal companion object {

@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))
}
}
internal value class Buffer internal constructor(internal val value: ByteArray)

@Throws(IllegalArgumentException::class)
@Suppress("UnusedReceiverParameter")
internal inline fun Digest.initializeBuffer(
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.copy(): Buffer = Buffer(value.copyOf())

internal inline fun Buffer.commonUpdate(
input: Byte,
bufPosPlusPlus: Int,
Expand All @@ -59,7 +54,6 @@ internal inline fun Buffer.commonUpdate(
bufPosSet(0)
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.commonUpdate(
input: ByteArray,
offset: Int,
Expand Down Expand Up @@ -111,20 +105,31 @@ internal inline fun Buffer.commonUpdate(
bufPosSet(posBuf)
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.commonDigest(
input: ByteArray,
updateProtected: (ByteArray, Int, Int) -> Unit,
bufPosGet: () -> Int,
digestProtected: (buf: ByteArray, bufPos: Int) -> ByteArray,
resetProtected: () -> Unit,
bufPosSet: (zero: Int) -> Unit,
): ByteArray {
updateProtected(input, 0, input.size)
return commonDigest(bufPosGet(), digestProtected, resetProtected, bufPosSet)
}

internal inline fun Buffer.commonDigest(
bufPos: Int,
digestProtected: (buf: ByteArray, bufPos: Int) -> ByteArray,
reset: () -> Unit,
resetProtected: () -> Unit,
bufPosSet: (zero: Int) -> Unit,
): ByteArray {
// Zeroize any stale input that may be left in the buffer
value.fill(0, bufPos)
val final = digestProtected(value, bufPos)
reset()
return final
val digest = digestProtected(value, bufPos)
commonReset(resetProtected, bufPosSet)
return digest
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Buffer.commonReset(
resetProtected: () -> Unit,
bufPosSet: (zero: Int) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public actual abstract class Digest: MessageDigest, Algorithm, Cloneable, Copyab
* */
@Throws(IllegalArgumentException::class)
protected actual constructor(algorithm: String, blockSize: Int, digestLength: Int): super(algorithm) {
this.buf = Buffer.initialize(algorithm, blockSize, digestLength)
this.buf = initializeBuffer(algorithm, blockSize, digestLength)
this.digestLength = digestLength
this.bufPos = 0
}
Expand Down Expand Up @@ -127,22 +127,30 @@ public actual abstract class Digest: MessageDigest, Algorithm, Cloneable, Copyab
public actual final override fun digest(): ByteArray = buf.commonDigest(
bufPos = bufPos,
digestProtected = ::digestProtected,
reset = ::reset
resetProtected = ::resetProtected,
bufPosSet = { bufPos = it },
)

/**
* Updates the instance with provided [input], then completes the computation,
* performing final operations and returning the resultant array of bytes. The
* [Digest] is [reset] afterward.
* */
public actual final override fun digest(input: ByteArray): ByteArray {
updateProtected(input, 0, input.size)
return digest()
}
public actual final override fun digest(input: ByteArray): ByteArray = buf.commonDigest(
input = input,
updateProtected = ::updateProtected,
bufPosGet = ::bufPos,
digestProtected = ::digestProtected,
resetProtected = ::resetProtected,
bufPosSet = { bufPos = it },
)

// See Resettable interface documentation
public actual final override fun reset() {
buf.commonReset(::resetProtected) { bufPos = it }
buf.commonReset(
resetProtected = ::resetProtected,
bufPosSet = { bufPos = it },
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public actual abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Up
* */
@Throws(IllegalArgumentException::class)
protected actual constructor(algorithm: String, blockSize: Int, digestLength: Int) {
this.buf = Buffer.initialize(algorithm, blockSize, digestLength)
this.buf = initializeBuffer(algorithm, blockSize, digestLength)
this.algorithm = algorithm
this.digestLength = digestLength
this.bufPos = 0
Expand Down Expand Up @@ -124,22 +124,30 @@ public actual abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Up
public actual fun digest(): ByteArray = buf.commonDigest(
bufPos = bufPos,
digestProtected = ::digestProtected,
reset = ::reset,
resetProtected = ::resetProtected,
bufPosSet = { bufPos = it },
)

/**
* Updates the instance with provided [input], then completes the computation,
* performing final operations and returning the resultant array of bytes. The
* [Digest] is [reset] afterward.
* */
public actual fun digest(input: ByteArray): ByteArray {
updateProtected(input, 0, input.size)
return digest()
}
public actual fun digest(input: ByteArray): ByteArray = buf.commonDigest(
input = input,
updateProtected = ::updateProtected,
bufPosGet = ::bufPos,
digestProtected = ::digestProtected,
resetProtected = ::resetProtected,
bufPosSet = { bufPos = it },
)

// See Resettable interface documentation
public actual final override fun reset() {
buf.commonReset(::resetProtected) { bufPos = it }
buf.commonReset(
resetProtected = ::resetProtected,
bufPosSet = { bufPos = it },
)
}

/**
Expand Down
18 changes: 11 additions & 7 deletions library/xof/src/commonMain/kotlin/org/kotlincrypto/core/xof/Xof.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("KotlinRedundantDiagnosticSuppress", "NOTHING_TO_INLINE")

package org.kotlincrypto.core.xof

import org.kotlincrypto.core.*
Expand Down Expand Up @@ -209,9 +211,7 @@ public sealed class Xof<A: XofAlgorithm>: Algorithm, Copyable<Xof<A>>, Resettabl

@JvmStatic
public fun leftEncode(value: Long): ByteArray {
val lo = value.toInt()
val hi = value.rotateLeft(32).toInt()
return encode(lo = lo, hi = hi, left = true)
return encode(lo = value.lo(), hi = value.hi(), left = true)
}

@JvmStatic
Expand All @@ -226,9 +226,7 @@ public sealed class Xof<A: XofAlgorithm>: Algorithm, Copyable<Xof<A>>, Resettabl

@JvmStatic
public fun rightEncode(value: Long): ByteArray {
val lo = value.toInt()
val hi = value.rotateLeft(32).toInt()
return encode(lo = lo, hi = hi, left = false)
return encode(lo = value.lo(), hi = value.hi(), left = false)
}

@JvmStatic
Expand All @@ -237,7 +235,13 @@ public sealed class Xof<A: XofAlgorithm>: Algorithm, Copyable<Xof<A>>, Resettabl
}

@JvmStatic
private fun encode(lo: Int, hi: Int, left: Boolean): ByteArray {
private inline fun Long.lo(): Int = toInt()

@JvmStatic
private inline fun Long.hi(): Int = rotateLeft(32).toInt()

@JvmStatic
private inline fun encode(lo: Int, hi: Int, left: Boolean): ByteArray {
val a = if (hi == 0) {
if (lo == 0) {
// If it's zero, return early
Expand Down
Loading