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

Optimize addData #23

Merged
merged 2 commits into from
Dec 23, 2024
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 @@ -26,7 +26,14 @@ private const val TIME_MEASURE = 4
abstract class KeccakPBenchmarkBase<N: Number> {

protected abstract val state: KState<N, *>
protected abstract fun Int.toN(): N

@Suppress("UNCHECKED_CAST")
private fun Int.toN(): N = when (state) {
is F1600 -> toLong()
is F800 -> toInt()
is F400 -> toShort()
is F200 -> toByte()
} as N

@Setup
fun setup() {
Expand All @@ -36,56 +43,64 @@ abstract class KeccakPBenchmarkBase<N: Number> {

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.MICROSECONDS)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Warmup(iterations = ITERATIONS, time = TIME_WARMUP)
@Measurement(iterations = ITERATIONS, time = TIME_MEASURE)
open class F1600Benchmark: KeccakPBenchmarkBase<Long>() {

override val state = F1600()
override fun Int.toN(): Long = toLong()

@Benchmark
fun benchmark() = state.keccakP()
fun keccakP() = state.keccakP()

@Benchmark
fun addData() { repeat(10) { state.addData(it, 10) } }
}

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.MICROSECONDS)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Warmup(iterations = ITERATIONS, time = TIME_WARMUP)
@Measurement(iterations = ITERATIONS, time = TIME_MEASURE)
open class F800Benchmark: KeccakPBenchmarkBase<Int>() {

override val state = F800()
override fun Int.toN(): Int = this

@Benchmark
fun benchmark() = state.keccakP()
fun keccakP() = state.keccakP()

@Benchmark
fun addData() { repeat(10) { state.addData(it, 10) } }
}

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.MICROSECONDS)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Warmup(iterations = ITERATIONS, time = TIME_WARMUP)
@Measurement(iterations = ITERATIONS, time = TIME_MEASURE)
open class F400Benchmark: KeccakPBenchmarkBase<Short>() {

override val state = F400()
override fun Int.toN(): Short = toShort()

@Benchmark
fun benchmark() = state.keccakP()
fun keccakP() = state.keccakP()

@Benchmark
fun addData() { repeat(10) { state.addData(it, 10) } }
}

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.MICROSECONDS)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Warmup(iterations = ITERATIONS, time = TIME_WARMUP)
@Measurement(iterations = ITERATIONS, time = TIME_MEASURE)
open class F200Benchmark: KeccakPBenchmarkBase<Byte>() {

override val state = F200()
override fun Int.toN(): Byte = toByte()

@Benchmark
fun benchmark() = state.keccakP()
fun keccakP() = state.keccakP()

@Benchmark
fun addData() { repeat(10) { state.addData(it, 10) } }
}
22 changes: 15 additions & 7 deletions library/keccak/api/keccak.api
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
public final class org/kotlincrypto/sponges/keccak/F1600 : org/kotlincrypto/sponges/keccak/State {
public fun <init> ()V
public synthetic fun XOR (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
public fun addData (IJ)V
public synthetic fun addData (ILjava/lang/Number;)V
public fun copy ()Lorg/kotlincrypto/sponges/keccak/F1600;
public synthetic fun copy ()Lorg/kotlincrypto/sponges/keccak/State;
public fun reset ()V
}

public final class org/kotlincrypto/sponges/keccak/F200 : org/kotlincrypto/sponges/keccak/State {
public fun <init> ()V
public synthetic fun XOR (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
public fun addData (IB)V
public synthetic fun addData (ILjava/lang/Number;)V
public fun copy ()Lorg/kotlincrypto/sponges/keccak/F200;
public synthetic fun copy ()Lorg/kotlincrypto/sponges/keccak/State;
public fun reset ()V
}

public final class org/kotlincrypto/sponges/keccak/F400 : org/kotlincrypto/sponges/keccak/State {
public fun <init> ()V
public synthetic fun XOR (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
public synthetic fun addData (ILjava/lang/Number;)V
public fun addData (IS)V
public fun copy ()Lorg/kotlincrypto/sponges/keccak/F400;
public synthetic fun copy ()Lorg/kotlincrypto/sponges/keccak/State;
public fun reset ()V
}

public final class org/kotlincrypto/sponges/keccak/F800 : org/kotlincrypto/sponges/keccak/State {
public fun <init> ()V
public synthetic fun XOR (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
public fun addData (II)V
public synthetic fun addData (ILjava/lang/Number;)V
public fun copy ()Lorg/kotlincrypto/sponges/keccak/F800;
public synthetic fun copy ()Lorg/kotlincrypto/sponges/keccak/State;
public fun reset ()V
}

public final class org/kotlincrypto/sponges/keccak/KeccakPKt {
Expand All @@ -46,13 +54,13 @@ public final class org/kotlincrypto/sponges/keccak/KeccakPKt {

public abstract class org/kotlincrypto/sponges/keccak/State : java/util/Collection, kotlin/jvm/internal/markers/KMappedMarker {
protected static final field Companion Lorg/kotlincrypto/sponges/keccak/State$Companion;
protected final field array [Ljava/lang/Number;
public final field roundCount B
public synthetic fun <init> (B[Ljava/lang/Number;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
protected abstract fun XOR (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
public fun add (Ljava/lang/Number;)Z
public synthetic fun add (Ljava/lang/Object;)Z
public fun addAll (Ljava/util/Collection;)Z
public final fun addData (ILjava/lang/Number;)V
public abstract fun addData (ILjava/lang/Number;)V
public fun clear ()V
public final fun contains (Ljava/lang/Number;)Z
public final fun contains (Ljava/lang/Object;)Z
Expand All @@ -65,7 +73,7 @@ public abstract class org/kotlincrypto/sponges/keccak/State : java/util/Collecti
public fun remove (Ljava/lang/Object;)Z
public fun removeAll (Ljava/util/Collection;)Z
public fun removeIf (Ljava/util/function/Predicate;)Z
public final fun reset ()V
public abstract fun reset ()V
public fun retainAll (Ljava/util/Collection;)Z
public final fun size ()I
public fun toArray ()[Ljava/lang/Object;
Expand Down
15 changes: 12 additions & 3 deletions library/keccak/api/keccak.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,53 @@
final class org.kotlincrypto.sponges.keccak/F1600 : org.kotlincrypto.sponges.keccak/State<kotlin/Long, org.kotlincrypto.sponges.keccak/F1600> { // org.kotlincrypto.sponges.keccak/F1600|null[0]
constructor <init>() // org.kotlincrypto.sponges.keccak/F1600.<init>|<init>(){}[0]

final fun addData(kotlin/Int, kotlin/Long) // org.kotlincrypto.sponges.keccak/F1600.addData|addData(kotlin.Int;kotlin.Long){}[0]
final fun copy(): org.kotlincrypto.sponges.keccak/F1600 // org.kotlincrypto.sponges.keccak/F1600.copy|copy(){}[0]
final fun reset() // org.kotlincrypto.sponges.keccak/F1600.reset|reset(){}[0]
}

final class org.kotlincrypto.sponges.keccak/F200 : org.kotlincrypto.sponges.keccak/State<kotlin/Byte, org.kotlincrypto.sponges.keccak/F200> { // org.kotlincrypto.sponges.keccak/F200|null[0]
constructor <init>() // org.kotlincrypto.sponges.keccak/F200.<init>|<init>(){}[0]

final fun addData(kotlin/Int, kotlin/Byte) // org.kotlincrypto.sponges.keccak/F200.addData|addData(kotlin.Int;kotlin.Byte){}[0]
final fun copy(): org.kotlincrypto.sponges.keccak/F200 // org.kotlincrypto.sponges.keccak/F200.copy|copy(){}[0]
final fun reset() // org.kotlincrypto.sponges.keccak/F200.reset|reset(){}[0]
}

final class org.kotlincrypto.sponges.keccak/F400 : org.kotlincrypto.sponges.keccak/State<kotlin/Short, org.kotlincrypto.sponges.keccak/F400> { // org.kotlincrypto.sponges.keccak/F400|null[0]
constructor <init>() // org.kotlincrypto.sponges.keccak/F400.<init>|<init>(){}[0]

final fun addData(kotlin/Int, kotlin/Short) // org.kotlincrypto.sponges.keccak/F400.addData|addData(kotlin.Int;kotlin.Short){}[0]
final fun copy(): org.kotlincrypto.sponges.keccak/F400 // org.kotlincrypto.sponges.keccak/F400.copy|copy(){}[0]
final fun reset() // org.kotlincrypto.sponges.keccak/F400.reset|reset(){}[0]
}

final class org.kotlincrypto.sponges.keccak/F800 : org.kotlincrypto.sponges.keccak/State<kotlin/Int, org.kotlincrypto.sponges.keccak/F800> { // org.kotlincrypto.sponges.keccak/F800|null[0]
constructor <init>() // org.kotlincrypto.sponges.keccak/F800.<init>|<init>(){}[0]

final fun addData(kotlin/Int, kotlin/Int) // org.kotlincrypto.sponges.keccak/F800.addData|addData(kotlin.Int;kotlin.Int){}[0]
final fun copy(): org.kotlincrypto.sponges.keccak/F800 // org.kotlincrypto.sponges.keccak/F800.copy|copy(){}[0]
final fun reset() // org.kotlincrypto.sponges.keccak/F800.reset|reset(){}[0]
}

sealed class <#A: kotlin/Number, #B: org.kotlincrypto.sponges.keccak/State<#A, #B>> org.kotlincrypto.sponges.keccak/State : kotlin.collections/Collection<#A> { // org.kotlincrypto.sponges.keccak/State|null[0]
constructor <init>(kotlin/Byte, kotlin/Array<#A>) // org.kotlincrypto.sponges.keccak/State.<init>|<init>(kotlin.Byte;kotlin.Array<1:0>){}[0]

final val array // org.kotlincrypto.sponges.keccak/State.array|{}array[0]
final fun <get-array>(): kotlin/Array<#A> // org.kotlincrypto.sponges.keccak/State.array.<get-array>|<get-array>(){}[0]
final val roundCount // org.kotlincrypto.sponges.keccak/State.roundCount|{}roundCount[0]
final fun <get-roundCount>(): kotlin/Byte // org.kotlincrypto.sponges.keccak/State.roundCount.<get-roundCount>|<get-roundCount>(){}[0]
final val size // org.kotlincrypto.sponges.keccak/State.size|{}size[0]
final fun <get-size>(): kotlin/Int // org.kotlincrypto.sponges.keccak/State.size.<get-size>|<get-size>(){}[0]

abstract fun (#A).XOR(#A): #A // org.kotlincrypto.sponges.keccak/State.XOR|XOR@1:0(1:0){}[0]
abstract fun addData(kotlin/Int, #A) // org.kotlincrypto.sponges.keccak/State.addData|addData(kotlin.Int;1:0){}[0]
abstract fun copy(): #B // org.kotlincrypto.sponges.keccak/State.copy|copy(){}[0]
final fun addData(kotlin/Int, #A) // org.kotlincrypto.sponges.keccak/State.addData|addData(kotlin.Int;1:0){}[0]
abstract fun reset() // org.kotlincrypto.sponges.keccak/State.reset|reset(){}[0]
final fun contains(#A): kotlin/Boolean // org.kotlincrypto.sponges.keccak/State.contains|contains(1:0){}[0]
final fun containsAll(kotlin.collections/Collection<#A>): kotlin/Boolean // org.kotlincrypto.sponges.keccak/State.containsAll|containsAll(kotlin.collections.Collection<1:0>){}[0]
final fun get(kotlin/Int): #A // org.kotlincrypto.sponges.keccak/State.get|get(kotlin.Int){}[0]
final fun isEmpty(): kotlin/Boolean // org.kotlincrypto.sponges.keccak/State.isEmpty|isEmpty(){}[0]
final fun iterator(): kotlin.collections/Iterator<#A> // org.kotlincrypto.sponges.keccak/State.iterator|iterator(){}[0]
final fun reset() // org.kotlincrypto.sponges.keccak/State.reset|reset(){}[0]

final object Companion // org.kotlincrypto.sponges.keccak/State.Companion|null[0]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ package org.kotlincrypto.sponges.keccak
* @see [keccakP]
* */
public class F1600: State<Long, F1600> {
public constructor(): super(roundCount = 24, state = Array(P_LEN) { 0 })
private constructor(state: F1600): super(state.roundCount, state.lanes().copyOf())
public constructor(): super(roundCount = 24, array = Array(P_LEN) { 0 })
private constructor(state: F1600): super(state.roundCount, state.array.copyOf())
public override fun copy(): F1600 = F1600(this)
protected override fun Long.XOR(data: Long): Long = this xor data
@Throws(IndexOutOfBoundsException::class)
public override fun addData(index: Int, data: Long) { array[index] = array[index] xor data }
public override fun reset() { array.fill(0) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import kotlin.experimental.xor
* @see [keccakP]
* */
public class F200: State<Byte, F200> {
public constructor(): super(roundCount = 18, state = Array(P_LEN) { 0 })
private constructor(state: F200): super(state.roundCount, state.lanes().copyOf())
public constructor(): super(roundCount = 18, array = Array(P_LEN) { 0 })
private constructor(state: F200): super(state.roundCount, state.array.copyOf())
public override fun copy(): F200 = F200(this)
protected override fun Byte.XOR(data: Byte): Byte = this xor data
@Throws(IndexOutOfBoundsException::class)
public override fun addData(index: Int, data: Byte) { array[index] = array[index] xor data }
public override fun reset() { array.fill(0) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import kotlin.experimental.xor
* @see [keccakP]
* */
public class F400: State<Short, F400> {
public constructor(): super(roundCount = 20, state = Array(P_LEN) { 0 })
private constructor(state: F400): super(state.roundCount, state.lanes().copyOf())
public constructor(): super(roundCount = 20, array = Array(P_LEN) { 0 })
private constructor(state: F400): super(state.roundCount, state.array.copyOf())
public override fun copy(): F400 = F400(this)
protected override fun Short.XOR(data: Short): Short = this xor data
@Throws(IndexOutOfBoundsException::class)
public override fun addData(index: Int, data: Short) { array[index] = array[index] xor data }
public override fun reset() { array.fill(0) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
**/
package org.kotlincrypto.sponges.keccak


/**
* [State] for Keccak-f[800]
*
* @see [keccakP]
* */
public class F800: State<Int, F800> {
public constructor(): super(roundCount = 22, state = Array(P_LEN) { 0 })
private constructor(state: F800): super(state.roundCount, state.lanes().copyOf())
public constructor(): super(roundCount = 22, array = Array(P_LEN) { 0 })
private constructor(state: F800): super(state.roundCount, state.array.copyOf())
public override fun copy(): F800 = F800(this)
protected override fun Int.XOR(data: Int): Int = this xor data
@Throws(IndexOutOfBoundsException::class)
public override fun addData(index: Int, data: Int) { array[index] = array[index] xor data }
public override fun reset() { array.fill(0) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,35 @@ public sealed class State<N: Number, T: State<N, T>>(
@JvmField
public val roundCount: Byte,

private val state: Array<N>,
@JvmField
protected val array: Array<N>,
): Collection<N> {

init {
// state.size will always be 25
require(state.size == P_LEN) { "state.size must equal $P_LEN" }
require(array.size == P_LEN) { "state.size must equal $P_LEN" }
}

@Throws(IndexOutOfBoundsException::class)
public operator fun get(index: Int): N = state[index]
public operator fun get(index: Int): N = array[index]

/**
* Adds [data] to [state] at the provided [index]
* Adds [data] to [data] at the provided [index]
*
* @throws [IndexOutOfBoundsException] if [index] is not between 0 and 24 (inclusive)
* */
@Throws(IndexOutOfBoundsException::class)
public fun addData(index: Int, data: N) {
state[index] = state[index] XOR data
}
public abstract fun addData(index: Int, data: N)

public abstract fun copy(): T

public fun reset() {
val zero = when (this) {
is F1600 -> 0L
is F800 -> 0
is F400 -> 0.toShort()
is F200 -> 0.toByte()
}
@Suppress("UNCHECKED_CAST")
state.fill(zero as N)
}
public abstract fun reset()

final override val size: Int get() = P_LEN
final override fun isEmpty(): Boolean = false
final override operator fun contains(element: N): Boolean = state.contains(element)
final override operator fun contains(element: N): Boolean = array.contains(element)
final override fun iterator(): Iterator<N> = object : Iterator<N> {
private val delegate = state.iterator()
private val delegate = array.iterator()

override fun hasNext(): Boolean = delegate.hasNext()
override fun next(): N = delegate.next()
Expand All @@ -86,16 +76,14 @@ public sealed class State<N: Number, T: State<N, T>>(
}
final override fun containsAll(elements: Collection<N>): Boolean {
elements.forEach { n ->
if (!state.contains(n)) return false
if (!array.contains(n)) return false
}

return true
}

protected abstract infix fun N.XOR(data: N): N

@JvmSynthetic
internal fun lanes(): Array<N> = state
internal fun lanes(): Array<N> = array

protected companion object {
internal const val P_LEN: Int = 25
Expand Down
Loading