missing initial files + publishing

This commit is contained in:
sergeych committed 2023-11-22 23:56:18 +03:00
1 parent aaa8c436b0
commit f429cfe418
25 files changed
+870

No files matched your search

@@ -0,0 +1,183 @@
package org.komputing.khash.keccak
import com.ionspin.kotlin.bignum.integer.BigInteger
import org.komputing.khash.keccak.extensions.fillWith
import kotlin.math.min
object Keccak {
private val BIT_65 = BigInteger.ONE shl (64)
private val MAX_64_BITS = BIT_65 - BigInteger.ONE
fun digest(value: ByteArray, parameter: KeccakParameter): ByteArray {
val uState = IntArray(200)
val uMessage = convertToUInt(value)
var blockSize = 0
var inputOffset = 0
// Absorbing phase
while (inputOffset < uMessage.size) {
blockSize = min(uMessage.size - inputOffset, parameter.rateInBytes)
for (i in 0 until blockSize) {
uState[i] = uState[i] xor uMessage[i + inputOffset]
}
inputOffset += blockSize
if (blockSize == parameter.rateInBytes) {
doF(uState)
blockSize = 0
}
}
// Padding phase
uState[blockSize] = uState[blockSize] xor parameter.d
if (parameter.d and 0x80 != 0 && blockSize == parameter.rateInBytes - 1) {
doF(uState)
}
uState[parameter.rateInBytes - 1] = uState[parameter.rateInBytes - 1] xor 0x80
doF(uState)
// Squeezing phase
val byteResults = mutableListOf<Byte>()
var tOutputLen = parameter.outputLengthInBytes
while (tOutputLen > 0) {
blockSize = min(tOutputLen, parameter.rateInBytes)
for (i in 0 until blockSize) {
byteResults.add(uState[i].toByte().toInt().toByte())
}
tOutputLen -= blockSize
if (tOutputLen > 0) {
doF(uState)
}
}
return byteResults.toByteArray()
}
private fun doF(uState: IntArray) {
val lState = Array(5) { Array(5) { BigInteger.ZERO } }
for (i in 0..4) {
for (j in 0..4) {
val data = IntArray(8)
val index = 8 * (i + 5 * j)
uState.copyInto(data, 0, index, index + data.size)
lState[i][j] = convertFromLittleEndianTo64(data)
}
}
roundB(lState)
uState.fillWith(0)
for (i in 0..4) {
for (j in 0..4) {
val data = convertFrom64ToLittleEndian(lState[i][j])
data.copyInto(uState, 8 * (i + 5 * j))
}
}
}
/**
* Permutation on the given state.
*/
private fun roundB(state: Array<Array<BigInteger>>) {
var lfsrState = 1
for (round in 0..23) {
val c = arrayOfNulls<BigInteger>(5)
val d = arrayOfNulls<BigInteger>(5)
// θ step
for (i in 0..4) {
c[i] = state[i][0].xor(state[i][1]).xor(state[i][2]).xor(state[i][3]).xor(state[i][4])
}
for (i in 0..4) {
d[i] = c[(i + 4) % 5]!!.xor(c[(i + 1) % 5]!!.leftRotate64(1))
}
for (i in 0..4) {
for (j in 0..4) {
state[i][j] = state[i][j].xor(d[i]!!)
}
}
// ρ and π steps
var x = 1
var y = 0
var current = state[x][y]
for (i in 0..23) {
val tX = x
x = y
y = (2 * tX + 3 * y) % 5
val shiftValue = current
current = state[x][y]
state[x][y] = shiftValue.leftRotate64Safely((i + 1) * (i + 2) / 2)
}
// χ step
for (j in 0..4) {
val t = arrayOfNulls<BigInteger>(5)
for (i in 0..4) {
t[i] = state[i][j]
}
for (i in 0..4) {
// ~t[(i + 1) % 5]
val invertVal = t[(i + 1) % 5]!!.xor(MAX_64_BITS)
// t[i] ^ ((~t[(i + 1) % 5]) & t[(i + 2) % 5])
state[i][j] = t[i]!!.xor(invertVal.and(t[(i + 2) % 5]!!))
}
}
// ι step
for (i in 0..6) {
lfsrState = (lfsrState shl 1 xor (lfsrState shr 7) * 0x71) % 256
// pow(2, i) - 1
val bitPosition = (1 shl i) - 1
if (lfsrState and 2 != 0) {
state[0][0] = state[0][0].xor(BigInteger.ONE shl bitPosition)
}
}
}
}
/**
* Converts the given [data] array to an [IntArray] containing UInt values.
*/
private fun convertToUInt(data: ByteArray) = IntArray(data.size) {
data[it].toInt() and 0xFF
}
/**
* Converts the given [data] array containing the little endian representation of a number to a [BigInteger].
*/
private fun convertFromLittleEndianTo64(data: IntArray): BigInteger {
val value = data.map { it.toString(16) }
.map { if (it.length == 2) it else "0$it" }
.reversed()
.joinToString("")
return BigInteger.parseString(value, 16)
}
/**
* Converts the given [BigInteger] to a little endian representation as an [IntArray].
*/
private fun convertFrom64ToLittleEndian(uLong: BigInteger): IntArray {
val asHex = uLong.toString(16)
val asHexPadded = "0".repeat((8 * 2) - asHex.length) + asHex
return IntArray(8) {
((7 - it) * 2).let { pos ->
asHexPadded.substring(pos, pos + 2).toInt(16)
}
}
}
private fun BigInteger.leftRotate64Safely(rotate: Int) = leftRotate64(rotate % 64)
private fun BigInteger.leftRotate64(rotate: Int) = (this shr (64 - rotate)).add(this shl rotate).mod(BIT_65)
}
@@ -0,0 +1,22 @@
@file:Suppress("unused")
package org.komputing.khash.keccak
/**
* Parameters defining the FIPS 202 standard.
*/
enum class KeccakParameter(val rateInBytes: Int,val outputLengthInBytes: Int, val d: Int) {
KECCAK_224(144, 28, 0x01),
KECCAK_256(136, 32, 0x01),
KECCAK_384(104, 48, 0x01),
KECCAK_512(72, 64, 0x01),
SHA3_224(144, 28, 0x06),
SHA3_256(136, 32, 0x06),
SHA3_384(104, 48, 0x06),
SHA3_512(72, 64, 0x06),
SHAKE128(168, 32, 0x1F),
SHAKE256(136, 64, 0x1F)
}
@@ -0,0 +1,42 @@
package org.komputing.khash.keccak.extensions
/**
* Assigns the specified int value to each element of the specified
* range in the specified array of ints. The range to be filled
* extends from index <tt>fromIndex</tt>, inclusive, to index
* <tt>toIndex</tt>, exclusive. (If <tt>fromIndex==toIndex</tt>, the
* range to be filled is empty.)
*
* @param fromIndex the index of the first element (inclusive) to be
* filled with the specified value
* @param toIndex the index of the last element (exclusive) to be
* filled with the specified value
* @param value the value to be stored in all elements of the array
* @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
* @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
* <tt>toIndex &gt; a.length</tt>
*/
internal fun IntArray.fillWith(value: Int, fromIndex: Int = 0, toIndex: Int = this.size) {
if (fromIndex > toIndex) {
throw IllegalArgumentException(
"fromIndex($fromIndex) > toIndex($toIndex)"
)
}
if (fromIndex < 0) {
throw ArrayIndexOutOfBoundsException(fromIndex)
}
if (toIndex > this.size) {
throw ArrayIndexOutOfBoundsException(toIndex)
}
for (i in fromIndex until toIndex)
this[i] = value
}
/**
* Constructs a new [ArrayIndexOutOfBoundsException]
* class with an argument indicating the illegal index.
* @param index the illegal index.
*/
internal class ArrayIndexOutOfBoundsException(index: Int) : Throwable("Array index out of range: $index")
@@ -0,0 +1,19 @@
@file:Suppress("unused")
package org.komputing.khash.keccak.extensions
import org.komputing.khash.keccak.Keccak
import org.komputing.khash.keccak.KeccakParameter
/**
* Computes the proper Keccak digest of [this] byte array based on the given [parameter]
*/
fun ByteArray.digestKeccak(parameter: KeccakParameter): ByteArray {
return Keccak.digest(this, parameter)
}
/**
* Computes the proper Keccak digest of [this] string based on the given [parameter]
*/
fun String.digestKeccak(parameter: KeccakParameter): ByteArray {
return Keccak.digest(encodeToByteArray(), parameter)
}