A bit of cleanup, a bit of profiling
This commit is contained in:
parent
2bbfefb56c
commit
7ce350825e
@ -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()
|
||||
|
||||
if (finalBlock) {
|
||||
// v[14] = v[14] xor 0xFFFFFFFFFFFFFFFFUL
|
||||
v[14] = v[14].inv()
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ import com.ionspin.kotlin.crypto.SRNG
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
|
||||
import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction
|
||||
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.util.*
|
||||
|
||||
@ -161,7 +161,7 @@ class Argon2(
|
||||
): ArgonBlockPointer {
|
||||
//Calculate first pass
|
||||
val zeroesBlock = ArgonBlock()
|
||||
val firstPass = inplaceCompressionFunctionG(
|
||||
val firstPass = compressionFunctionG(
|
||||
zeroesBlock.getBlockPointer(),
|
||||
ArgonBlock(iteration.toULong().toLittleEndianUByteArray() +
|
||||
lane.toULong().toLittleEndianUByteArray() +
|
||||
@ -175,7 +175,7 @@ class Argon2(
|
||||
addressBlock,
|
||||
false
|
||||
)
|
||||
val secondPass = inplaceCompressionFunctionG(
|
||||
val secondPass = compressionFunctionG(
|
||||
zeroesBlock.getBlockPointer(),
|
||||
firstPass,
|
||||
firstPass,
|
||||
@ -330,7 +330,7 @@ class Argon2(
|
||||
accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1))
|
||||
}
|
||||
//Hash the xored last blocks
|
||||
val hash = argonBlake2bArbitraryLenghtHash(acc.getAsUByteArray(), tagLength)
|
||||
val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength)
|
||||
matrix.clearMatrix()
|
||||
return hash
|
||||
|
||||
@ -391,7 +391,7 @@ class Argon2(
|
||||
)
|
||||
|
||||
matrix.setBlockAt(lane, column,
|
||||
inplaceCompressionFunctionG(
|
||||
compressionFunctionG(
|
||||
matrix.getBlockPointer(lane, previousColumn),
|
||||
matrix.getBlockPointer(l,z),
|
||||
matrix.getBlockPointer(lane,column),
|
||||
|
@ -38,6 +38,7 @@ object Argon2Utils {
|
||||
const val R3 = 16
|
||||
const val R4 = 63
|
||||
|
||||
//Based on Blake2b mix
|
||||
internal fun inplaceMixRound(v : ULongArray) : ULongArray{
|
||||
mix(v, 0, 4, 8, 12)
|
||||
mix(v, 1, 5, 9, 13)
|
||||
@ -47,38 +48,7 @@ object Argon2Utils {
|
||||
mix(v, 1, 6, 11, 12)
|
||||
mix(v, 2, 7, 8, 13)
|
||||
mix(v, 3, 4, 9, 14)
|
||||
return v //Just for chaining, array is already mixed
|
||||
}
|
||||
|
||||
//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
|
||||
return v //Just for chaining, array is mixed in place
|
||||
}
|
||||
|
||||
//Based on Blake2b mix
|
||||
@ -102,14 +72,9 @@ object Argon2Utils {
|
||||
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,
|
||||
referenceBlock: ArgonBlockPointer,
|
||||
currentBlock: ArgonBlockPointer,
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
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
|
||||
* or a UByteArray block
|
||||
@ -34,7 +36,7 @@ interface ArgonBlockPointer {
|
||||
operator fun set(blockPosition: Int, value: UByte)
|
||||
|
||||
infix fun xorInplaceWith(other: ArgonBlockPointer) : ArgonBlockPointer {
|
||||
(0 until 1024).forEach {
|
||||
for (it in 0 until 1024) {
|
||||
this[it] = this[it] xor other[it]
|
||||
}
|
||||
return this //For chaining
|
||||
@ -171,7 +173,6 @@ fun ArgonBlockPointer.getUIntFromPosition(positionInBlock: Int) : UInt {
|
||||
}
|
||||
|
||||
fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) {
|
||||
println("Expensive set")
|
||||
blockValue.copyInto(
|
||||
storage,
|
||||
getBlockStartPositionPointer(rowPosition, columnPosition)
|
||||
@ -271,7 +272,7 @@ inline class ArgonBlock internal constructor(internal val storage: UByteArray) {
|
||||
}
|
||||
|
||||
override fun getAsUByteArray(): UByteArray {
|
||||
return storageBlock.storage.slice(blockStartPosition until blockStartPosition + 1024).toUByteArray()
|
||||
return storageBlock.storage
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.keyderivation.argon2.Argon2
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType
|
||||
import com.ionspin.kotlin.crypto.util.testBlocking
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
@ -127,25 +130,28 @@ class ReadmeTest {
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalTime
|
||||
@Test
|
||||
fun argon2StringExample() {
|
||||
fun argon2StringExample() = testBlocking {
|
||||
val argon2Instance = Argon2(
|
||||
password = "Password",
|
||||
salt = "RandomSalt",
|
||||
parallelism = 4,
|
||||
parallelism = 1,
|
||||
tagLength = 64U,
|
||||
requestedMemorySize = 32U, //Travis build on mac fails with higher values
|
||||
numberOfIterations = 4,
|
||||
requestedMemorySize = 4096U, //Travis build on mac fails with higher values
|
||||
numberOfIterations = 100,
|
||||
key = "",
|
||||
associatedData = "",
|
||||
argonType = ArgonType.Argon2id
|
||||
)
|
||||
val time = measureTime {
|
||||
val tag = argon2Instance.derive()
|
||||
val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "")
|
||||
val expectedTagString = "ca134003c9f9f76ca8869359c1d9065603ec54ac30f5158f06af647cacaef2c1c3e" +
|
||||
"c71e81960278c0596febc64125acbbe5959146db1c128199a1b7cb38982a9"
|
||||
val expectedTagString = "27c61b6538ef9f4a1250f8712cac09fc4329969295f9440249437d38c1617a005c2702d76a8a59e4cda2dfba48e1132261dacdfd31296945906992ea32f1d06e"
|
||||
println("Tag: ${tagString}")
|
||||
assertEquals(tagString, expectedTagString)
|
||||
}
|
||||
println("Time $time")
|
||||
|
||||
}
|
||||
|
||||
|
@ -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.ArgonBlock
|
||||
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextUBytes
|
||||
import kotlin.test.Test
|
||||
@ -75,9 +76,10 @@ class Argon2Test {
|
||||
6500029010075826286U,
|
||||
16957672821843227543U
|
||||
)
|
||||
val result = Argon2Utils.mixRound(input)
|
||||
val preparedInput = input.chunked(8).map { it.toTypedArray().fromLittleEndianArrayToULong() }.toULongArray()
|
||||
val result = Argon2Utils.inplaceMixRound(preparedInput)
|
||||
assertTrue {
|
||||
expected.contentEquals(result)
|
||||
expected.contentEquals(result.toTypedArray())
|
||||
}
|
||||
|
||||
}
|
||||
@ -246,7 +248,7 @@ class Argon2Test {
|
||||
val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer()
|
||||
val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer()
|
||||
val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer()
|
||||
val resultWithoutXorAndAllocations = Argon2Utils.inplaceCompressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false)
|
||||
val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false)
|
||||
assertTrue {
|
||||
expectedWithoutXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray())
|
||||
}
|
||||
@ -391,7 +393,7 @@ class Argon2Test {
|
||||
val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer()
|
||||
val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer()
|
||||
val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer()
|
||||
val resultWithoutXorAndAllocations = Argon2Utils.inplaceCompressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true)
|
||||
val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true)
|
||||
assertTrue {
|
||||
expectedWithXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user