Skip to content

Commit

Permalink
Optimize addData (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
05nelsonm authored Dec 23, 2024
1 parent 5262fb2 commit f704761
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 58 deletions.
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

0 comments on commit f704761

Please sign in to comment.