A bit of cleanup, a bit of profiling

This commit is contained in:
Ugljesa Jovanovic 2020-05-23 18:38:50 +02:00 committed by Ugljesa Jovanovic
parent 2bbfefb56c
commit 7ce350825e
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
6 changed files with 35 additions and 62 deletions

View File

@ -134,7 +134,6 @@ class Blake2b(val key: UByteArray? = null, val hashLength: Int = 64) : Updatable
v[13] = v[13] xor (offsetCounter shr BITS_IN_WORD).ulongValue() v[13] = v[13] xor (offsetCounter shr BITS_IN_WORD).ulongValue()
if (finalBlock) { if (finalBlock) {
// v[14] = v[14] xor 0xFFFFFFFFFFFFFFFFUL
v[14] = v[14].inv() v[14] = v[14].inv()
} }

View File

@ -23,7 +23,7 @@ import com.ionspin.kotlin.crypto.SRNG
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.inplaceCompressionFunctionG import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
import com.ionspin.kotlin.crypto.util.* import com.ionspin.kotlin.crypto.util.*
@ -161,7 +161,7 @@ class Argon2(
): ArgonBlockPointer { ): ArgonBlockPointer {
//Calculate first pass //Calculate first pass
val zeroesBlock = ArgonBlock() val zeroesBlock = ArgonBlock()
val firstPass = inplaceCompressionFunctionG( val firstPass = compressionFunctionG(
zeroesBlock.getBlockPointer(), zeroesBlock.getBlockPointer(),
ArgonBlock(iteration.toULong().toLittleEndianUByteArray() + ArgonBlock(iteration.toULong().toLittleEndianUByteArray() +
lane.toULong().toLittleEndianUByteArray() + lane.toULong().toLittleEndianUByteArray() +
@ -175,7 +175,7 @@ class Argon2(
addressBlock, addressBlock,
false false
) )
val secondPass = inplaceCompressionFunctionG( val secondPass = compressionFunctionG(
zeroesBlock.getBlockPointer(), zeroesBlock.getBlockPointer(),
firstPass, firstPass,
firstPass, firstPass,
@ -330,7 +330,7 @@ class Argon2(
accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1)) accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1))
} }
//Hash the xored last blocks //Hash the xored last blocks
val hash = argonBlake2bArbitraryLenghtHash(acc.getAsUByteArray(), tagLength) val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength)
matrix.clearMatrix() matrix.clearMatrix()
return hash return hash
@ -391,7 +391,7 @@ class Argon2(
) )
matrix.setBlockAt(lane, column, matrix.setBlockAt(lane, column,
inplaceCompressionFunctionG( compressionFunctionG(
matrix.getBlockPointer(lane, previousColumn), matrix.getBlockPointer(lane, previousColumn),
matrix.getBlockPointer(l,z), matrix.getBlockPointer(l,z),
matrix.getBlockPointer(lane,column), matrix.getBlockPointer(lane,column),

View File

@ -38,6 +38,7 @@ object Argon2Utils {
const val R3 = 16 const val R3 = 16
const val R4 = 63 const val R4 = 63
//Based on Blake2b mix
internal fun inplaceMixRound(v : ULongArray) : ULongArray{ internal fun inplaceMixRound(v : ULongArray) : ULongArray{
mix(v, 0, 4, 8, 12) mix(v, 0, 4, 8, 12)
mix(v, 1, 5, 9, 13) mix(v, 1, 5, 9, 13)
@ -47,38 +48,7 @@ object Argon2Utils {
mix(v, 1, 6, 11, 12) mix(v, 1, 6, 11, 12)
mix(v, 2, 7, 8, 13) mix(v, 2, 7, 8, 13)
mix(v, 3, 4, 9, 14) mix(v, 3, 4, 9, 14)
return v //Just for chaining, array is already mixed return v //Just for chaining, array is mixed in place
}
//based on Blake2b mixRound
internal fun mixRound(input: UByteArray): Array<ULong> {
var v = input.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toTypedArray()
v = mix(v, 0, 4, 8, 12)
v = mix(v, 1, 5, 9, 13)
v = mix(v, 2, 6, 10, 14)
v = mix(v, 3, 7, 11, 15)
v = mix(v, 0, 5, 10, 15)
v = mix(v, 1, 6, 11, 12)
v = mix(v, 2, 7, 8, 13)
v = mix(v, 3, 4, 9, 14)
return v
}
private fun inPlaceMix(v: UByteArray, a: Int, b: Int, c: Int, d: Int) {
}
//Based on Blake2b mix
private fun mix(v: Array<ULong>, a: Int, b: Int, c: Int, d: Int): Array<ULong> {
v[a] = (v[a] + v[b] + 2U * (v[a] and 0xFFFFFFFFUL) * (v[b] and 0xFFFFFFFFUL))
v[d] = (v[d] xor v[a]) rotateRight R1
v[c] = (v[c] + v[d] + 2U * (v[c] and 0xFFFFFFFFUL) * (v[d] and 0xFFFFFFFFUL))
v[b] = (v[b] xor v[c]) rotateRight R2
v[a] = (v[a] + v[b] + 2U * (v[a] and 0xFFFFFFFFUL) * (v[b] and 0xFFFFFFFFUL))
v[d] = (v[d] xor v[a]) rotateRight R3
v[c] = (v[c] + v[d] + 2U * (v[c] and 0xFFFFFFFFUL) * (v[d] and 0xFFFFFFFFUL))
v[b] = (v[b] xor v[c]) rotateRight R4
return v
} }
//Based on Blake2b mix //Based on Blake2b mix
@ -102,14 +72,9 @@ object Argon2Utils {
return result return result
} }
private fun copyIntoGBlockColumn(gBlock: UByteArray, columnPosition: Int, columnData: UByteArray) {
for (i in 0..7) {
val column = columnData.copyOfRange(i * 16, i * 16 + 16)
column.copyInto(gBlock, i * 128 + columnPosition * 16)
}
}
internal fun inplaceCompressionFunctionG(
internal fun compressionFunctionG(
previousBlock: ArgonBlockPointer, previousBlock: ArgonBlockPointer,
referenceBlock: ArgonBlockPointer, referenceBlock: ArgonBlockPointer,
currentBlock: ArgonBlockPointer, currentBlock: ArgonBlockPointer,

View File

@ -18,6 +18,8 @@
package com.ionspin.kotlin.crypto.keyderivation.argon2 package com.ionspin.kotlin.crypto.keyderivation.argon2
import com.ionspin.kotlin.crypto.util.xor
/** /**
* Represents a pointer to a Argon2 Block, this abstracts what the backing structure is, a Argon 2 Matrix or * Represents a pointer to a Argon2 Block, this abstracts what the backing structure is, a Argon 2 Matrix or
* or a UByteArray block * or a UByteArray block
@ -34,7 +36,7 @@ interface ArgonBlockPointer {
operator fun set(blockPosition: Int, value: UByte) operator fun set(blockPosition: Int, value: UByte)
infix fun xorInplaceWith(other: ArgonBlockPointer) : ArgonBlockPointer { infix fun xorInplaceWith(other: ArgonBlockPointer) : ArgonBlockPointer {
(0 until 1024).forEach { for (it in 0 until 1024) {
this[it] = this[it] xor other[it] this[it] = this[it] xor other[it]
} }
return this //For chaining return this //For chaining
@ -171,7 +173,6 @@ fun ArgonBlockPointer.getUIntFromPosition(positionInBlock: Int) : UInt {
} }
fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) { fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) {
println("Expensive set")
blockValue.copyInto( blockValue.copyInto(
storage, storage,
getBlockStartPositionPointer(rowPosition, columnPosition) getBlockStartPositionPointer(rowPosition, columnPosition)
@ -271,7 +272,7 @@ inline class ArgonBlock internal constructor(internal val storage: UByteArray) {
} }
override fun getAsUByteArray(): UByteArray { override fun getAsUByteArray(): UByteArray {
return storageBlock.storage.slice(blockStartPosition until blockStartPosition + 1024).toUByteArray() return storageBlock.storage
} }
} }

View File

@ -21,9 +21,12 @@ import com.ionspin.kotlin.crypto.hash.sha.Sha256
import com.ionspin.kotlin.crypto.hash.sha.Sha512 import com.ionspin.kotlin.crypto.hash.sha.Sha512
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2
import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType
import com.ionspin.kotlin.crypto.util.testBlocking
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
/** /**
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
@ -127,25 +130,28 @@ class ReadmeTest {
} }
@ExperimentalTime
@Test @Test
fun argon2StringExample() { fun argon2StringExample() = testBlocking {
val argon2Instance = Argon2( val argon2Instance = Argon2(
password = "Password", password = "Password",
salt = "RandomSalt", salt = "RandomSalt",
parallelism = 4, parallelism = 1,
tagLength = 64U, tagLength = 64U,
requestedMemorySize = 32U, //Travis build on mac fails with higher values requestedMemorySize = 4096U, //Travis build on mac fails with higher values
numberOfIterations = 4, numberOfIterations = 100,
key = "", key = "",
associatedData = "", associatedData = "",
argonType = ArgonType.Argon2id argonType = ArgonType.Argon2id
) )
val time = measureTime {
val tag = argon2Instance.derive() val tag = argon2Instance.derive()
val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "")
val expectedTagString = "ca134003c9f9f76ca8869359c1d9065603ec54ac30f5158f06af647cacaef2c1c3e" + val expectedTagString = "27c61b6538ef9f4a1250f8712cac09fc4329969295f9440249437d38c1617a005c2702d76a8a59e4cda2dfba48e1132261dacdfd31296945906992ea32f1d06e"
"c71e81960278c0596febc64125acbbe5959146db1c128199a1b7cb38982a9"
println("Tag: ${tagString}") println("Tag: ${tagString}")
assertEquals(tagString, expectedTagString) assertEquals(tagString, expectedTagString)
}
println("Time $time")
} }

View File

@ -20,6 +20,7 @@ package com.ionspin.kotlin.crypto.hash.argon
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils
import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonBlock import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonBlock
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong
import kotlin.random.Random import kotlin.random.Random
import kotlin.random.nextUBytes import kotlin.random.nextUBytes
import kotlin.test.Test import kotlin.test.Test
@ -75,9 +76,10 @@ class Argon2Test {
6500029010075826286U, 6500029010075826286U,
16957672821843227543U 16957672821843227543U
) )
val result = Argon2Utils.mixRound(input) val preparedInput = input.chunked(8).map { it.toTypedArray().fromLittleEndianArrayToULong() }.toULongArray()
val result = Argon2Utils.inplaceMixRound(preparedInput)
assertTrue { assertTrue {
expected.contentEquals(result) expected.contentEquals(result.toTypedArray())
} }
} }
@ -246,7 +248,7 @@ class Argon2Test {
val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer() val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer()
val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer() val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer()
val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer() val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer()
val resultWithoutXorAndAllocations = Argon2Utils.inplaceCompressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false) val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false)
assertTrue { assertTrue {
expectedWithoutXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray()) expectedWithoutXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray())
} }
@ -391,7 +393,7 @@ class Argon2Test {
val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer() val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer()
val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer() val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer()
val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer() val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer()
val resultWithoutXorAndAllocations = Argon2Utils.inplaceCompressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true) val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true)
assertTrue { assertTrue {
expectedWithXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray()) expectedWithXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray())
} }