Further reduction in allocations
This commit is contained in:
		
							parent
							
								
									3902b90b57
								
							
						
					
					
						commit
						4142549d2e
					
				@ -24,6 +24,7 @@ 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.compressionFunctionG
 | 
			
		||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.inplaceCompressionFunctionG
 | 
			
		||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
 | 
			
		||||
import com.ionspin.kotlin.crypto.util.*
 | 
			
		||||
 | 
			
		||||
@ -133,10 +134,10 @@ class Argon2(
 | 
			
		||||
    private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
 | 
			
		||||
 | 
			
		||||
    // State
 | 
			
		||||
    private val matrix: Argon2Matrix
 | 
			
		||||
    private val matrix: ArgonMatrix
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        matrix = Argon2Matrix(columnCount, parallelism)
 | 
			
		||||
        matrix = ArgonMatrix(columnCount, parallelism)
 | 
			
		||||
        validateArgonParameters(
 | 
			
		||||
            password,
 | 
			
		||||
            salt,
 | 
			
		||||
@ -156,25 +157,27 @@ class Argon2(
 | 
			
		||||
        iteration: Int,
 | 
			
		||||
        slice: Int,
 | 
			
		||||
        lane: Int,
 | 
			
		||||
        addressBlock: UByteArray,
 | 
			
		||||
        addressBlock: ArgonBlockPointer,
 | 
			
		||||
        addressCounter: ULong
 | 
			
		||||
    ): UByteArray {
 | 
			
		||||
    ): ArgonBlockPointer {
 | 
			
		||||
        //Calculate first pass
 | 
			
		||||
        val firstPass = compressionFunctionG(
 | 
			
		||||
            UByteArray(1024) { 0U },
 | 
			
		||||
            iteration.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
        val zeroesBlock = ArgonBlock()
 | 
			
		||||
        val firstPass = inplaceCompressionFunctionG(
 | 
			
		||||
            zeroesBlock.getBlockPointer(),
 | 
			
		||||
            ArgonBlock(iteration.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
                    lane.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
                    slice.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
                    blockCount.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
                    numberOfIterations.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
                    argonType.typeId.toULong().toLittleEndianUByteArray() +
 | 
			
		||||
                    addressCounter.toLittleEndianUByteArray() +
 | 
			
		||||
                    UByteArray(968) { 0U },
 | 
			
		||||
                    UByteArray(968) { 0U }
 | 
			
		||||
            ).getBlockPointer(),
 | 
			
		||||
            addressBlock,
 | 
			
		||||
            false
 | 
			
		||||
        )
 | 
			
		||||
        val secondPass = compressionFunctionG(
 | 
			
		||||
            UByteArray(1024) { 0U },
 | 
			
		||||
        val secondPass = inplaceCompressionFunctionG(
 | 
			
		||||
            zeroesBlock.getBlockPointer(),
 | 
			
		||||
            firstPass,
 | 
			
		||||
            firstPass,
 | 
			
		||||
            false
 | 
			
		||||
@ -188,46 +191,41 @@ class Argon2(
 | 
			
		||||
        slice: Int,
 | 
			
		||||
        lane: Int,
 | 
			
		||||
        column: Int,
 | 
			
		||||
        addressBlock: UByteArray?
 | 
			
		||||
        addressBlockPointer: ArgonBlockPointer?
 | 
			
		||||
    ): Pair<Int, Int> {
 | 
			
		||||
 | 
			
		||||
        val segmentIndex = (column % segmentLength)
 | 
			
		||||
        val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block
 | 
			
		||||
        val (j1, j2) = when (argonType) {
 | 
			
		||||
            ArgonType.Argon2d -> {
 | 
			
		||||
                val (previousBlockStart, previousBlockEnd) = if (column == 0) {
 | 
			
		||||
                    matrix.getBlockStartAndEndPositions(lane, columnCount - 1) //Get last block in the SAME lane
 | 
			
		||||
                val previousBlockStart = if (column == 0) {
 | 
			
		||||
                    matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane
 | 
			
		||||
                } else {
 | 
			
		||||
                    matrix.getBlockStartAndEndPositions(lane, column - 1)
 | 
			
		||||
                    matrix.getBlockPointer(lane, column - 1)
 | 
			
		||||
                }
 | 
			
		||||
                val bla = 1 until 3
 | 
			
		||||
                val first32Bit = matrix.sliceArray(previousBlockStart until previousBlockStart + 4).fromLittleEndianArrayToUInt()
 | 
			
		||||
                val second32Bit = matrix.sliceArray(previousBlockStart + 4 until previousBlockStart + 8).fromLittleEndianArrayToUInt()
 | 
			
		||||
                val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt()
 | 
			
		||||
                val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt()
 | 
			
		||||
 | 
			
		||||
                Pair(first32Bit, second32Bit)
 | 
			
		||||
            }
 | 
			
		||||
            ArgonType.Argon2i -> {
 | 
			
		||||
                val selectedAddressBlock =
 | 
			
		||||
                    addressBlock!!.sliceArray((independentIndex * 8) until (independentIndex * 8) + 8)
 | 
			
		||||
                val first32Bit = selectedAddressBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt()
 | 
			
		||||
                val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt()
 | 
			
		||||
                val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8)
 | 
			
		||||
                val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4)
 | 
			
		||||
                Pair(first32Bit, second32Bit)
 | 
			
		||||
            }
 | 
			
		||||
            ArgonType.Argon2id -> {
 | 
			
		||||
                if (iteration == 0 && (slice == 0 || slice == 1)) {
 | 
			
		||||
                    val selectedAddressBlock =
 | 
			
		||||
                        addressBlock!!.sliceArray((independentIndex * 8) until (independentIndex * 8) + 8)
 | 
			
		||||
                    val first32Bit = selectedAddressBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt()
 | 
			
		||||
                    val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt()
 | 
			
		||||
                    val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8)
 | 
			
		||||
                    val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4)
 | 
			
		||||
                    Pair(first32Bit, second32Bit)
 | 
			
		||||
                } else {
 | 
			
		||||
                    val (previousBlockStart, previousBlockEnd) = if (column == 0) {
 | 
			
		||||
                        matrix.getBlockStartAndEndPositions(lane, columnCount - 1) //Get last block in the SAME lane
 | 
			
		||||
                    val previousBlockStart = if (column == 0) {
 | 
			
		||||
                        matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane
 | 
			
		||||
                    } else {
 | 
			
		||||
                        matrix.getBlockStartAndEndPositions(lane, column - 1)
 | 
			
		||||
                        matrix.getBlockPointer(lane, column - 1)
 | 
			
		||||
                    }
 | 
			
		||||
                    val first32Bit = matrix.sliceArray(previousBlockStart until previousBlockStart + 4).fromLittleEndianArrayToUInt()
 | 
			
		||||
                    val second32Bit = matrix.sliceArray(previousBlockStart + 4 until previousBlockStart + 8).fromLittleEndianArrayToUInt()
 | 
			
		||||
                    val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt()
 | 
			
		||||
                    val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt()
 | 
			
		||||
                    Pair(first32Bit, second32Bit)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -356,14 +354,12 @@ class Argon2(
 | 
			
		||||
        val slice = segmentPosition.slice
 | 
			
		||||
        val lane = segmentPosition.lane
 | 
			
		||||
 | 
			
		||||
        var addressBlock: UByteArray? = null
 | 
			
		||||
        var addressBlock: ArgonBlockPointer? = null
 | 
			
		||||
        var addressCounter = 1UL //Starts from 1 in each segment as defined by the spec
 | 
			
		||||
 | 
			
		||||
        //Generate initial segment address block
 | 
			
		||||
        if (useIndependentAddressing) {
 | 
			
		||||
            addressBlock = UByteArray(1024) {
 | 
			
		||||
                0U
 | 
			
		||||
            }
 | 
			
		||||
            addressBlock = ArgonBlock().getBlockPointer()
 | 
			
		||||
            addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter)
 | 
			
		||||
            addressCounter++
 | 
			
		||||
        }
 | 
			
		||||
@ -396,12 +392,12 @@ class Argon2(
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            matrix.setBlockAt(lane, column,
 | 
			
		||||
                compressionFunctionG(
 | 
			
		||||
                    matrix.getBlockAt(lane, previousColumn),
 | 
			
		||||
                    matrix.getBlockAt(l,z),
 | 
			
		||||
                    matrix.getBlockAt(lane,column),
 | 
			
		||||
                inplaceCompressionFunctionG(
 | 
			
		||||
                    matrix.getBlockPointer(lane, previousColumn),
 | 
			
		||||
                    matrix.getBlockPointer(l,z),
 | 
			
		||||
                    matrix.getBlockPointer(lane,column),
 | 
			
		||||
                    true
 | 
			
		||||
                ).toUByteArray()
 | 
			
		||||
                ).getAsUByteArray()
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,233 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 *    Copyright 2019 Ugljesa Jovanovic
 | 
			
		||||
 *
 | 
			
		||||
 *    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 *    you may not use this file except in compliance with the License.
 | 
			
		||||
 *    You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 *    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 *    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 *    See the License for the specific language governing permissions and
 | 
			
		||||
 *    limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
 | 
			
		||||
 | 
			
		||||
package com.ionspin.kotlin.crypto.keyderivation.argon2
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by Ugljesa Jovanovic
 | 
			
		||||
 * ugljesa.jovanovic@ionspin.com
 | 
			
		||||
 * on 21-May-2020
 | 
			
		||||
 */
 | 
			
		||||
 class Argon2Matrix(val columnCount: Int, val rowCount: Int) {
 | 
			
		||||
 | 
			
		||||
    internal val storage: UByteArray = UByteArray(columnCount * rowCount * 1024)
 | 
			
		||||
 | 
			
		||||
    operator fun get(rowPosition: Int, columnPosition: Int, inBlockPosition: Int) : UByte {
 | 
			
		||||
        if (rowPosition > rowCount - 1) {
 | 
			
		||||
            throw RuntimeException("Invalid row (lane) requested: $rowPosition, rowCount: $rowCount")
 | 
			
		||||
        }
 | 
			
		||||
        if (columnPosition > columnCount - 1) {
 | 
			
		||||
            throw RuntimeException("Invalid column requested: $columnPosition, columnCount: $columnCount")
 | 
			
		||||
        }
 | 
			
		||||
        return storage[getBlockStartPositionPointer(rowPosition, columnPosition).intStorage + inBlockPosition]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    operator fun get(absolutePosition: Int) : UByte {
 | 
			
		||||
        return storage[absolutePosition]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    operator fun get(absolutePosition: BlockPointer) : UByte {
 | 
			
		||||
        return storage[absolutePosition.intStorage]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    operator fun set(rowPosition: Int, columnPosition: Int, inBlockPosition: Int, value: UByte) {
 | 
			
		||||
        storage[getBlockStartPositionPointer(rowPosition, columnPosition).intStorage + inBlockPosition] = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getBlockStartAndEndPositions(rowPosition: Int, columnPosition: Int) : Pair<BlockPointer, BlockPointer> {
 | 
			
		||||
        val start = getBlockStartPositionPointer(rowPosition, columnPosition)
 | 
			
		||||
        return Pair(
 | 
			
		||||
            start,
 | 
			
		||||
            start + 1024
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun sliceArray(indices: IntRange): UByteArray {
 | 
			
		||||
        return storage.sliceArray(indices)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getBlockAt(rowPosition: Int, columnPosition: Int) : UByteArray {
 | 
			
		||||
                println("Expensive get")
 | 
			
		||||
        return storage.copyOfRange(
 | 
			
		||||
            getBlockStartPositionPointer(rowPosition, columnPosition).intStorage,
 | 
			
		||||
            getBlockStartPositionPointer(rowPosition, columnPosition).intStorage + 1024
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) {
 | 
			
		||||
        println("Expensive set")
 | 
			
		||||
        blockValue.copyInto(
 | 
			
		||||
            storage,
 | 
			
		||||
            getBlockStartPositionPointer(rowPosition, columnPosition).intStorage
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private inline fun getBlockStartPositionPointer(rowPosition: Int, columnPosition: Int) : BlockPointer {
 | 
			
		||||
        return BlockPointer(rowPosition * columnCount * 1024 + columnPosition * 1024, this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    operator fun get(rowPosition: Int, columnPosition: Int) : UByteArray {
 | 
			
		||||
//        println("Expensive.")
 | 
			
		||||
//        return storage.copyOfRange(
 | 
			
		||||
//            rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024,
 | 
			
		||||
//            rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024 + 1024
 | 
			
		||||
//        )
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    internal fun clearMatrix() {
 | 
			
		||||
        for( index in storage.indices) { storage[index] = 0U }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
//TODO Decide: inline class without matrix reference?
 | 
			
		||||
class BlockPointer(val intStorage: Int, val matrix: Argon2Matrix) {
 | 
			
		||||
    operator fun rangeTo(other: BlockPointer): IntRange {
 | 
			
		||||
        return intStorage.rangeTo(other.intStorage)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    infix fun until(to: BlockPointer): IntRange {
 | 
			
		||||
        if (to.intStorage <= Int.MIN_VALUE) return IntRange.EMPTY
 | 
			
		||||
        return this .. BlockPointer(to.intStorage - 1, matrix)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline operator fun plus(other: BlockPointer) : BlockPointer {
 | 
			
		||||
        return BlockPointer(intStorage.plus(other.intStorage), matrix)
 | 
			
		||||
    }
 | 
			
		||||
    inline operator fun plus(other: Int) : BlockPointer {
 | 
			
		||||
        return BlockPointer(intStorage.plus(other), matrix)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline operator fun minus(other: BlockPointer) : BlockPointer {
 | 
			
		||||
        return BlockPointer(intStorage.minus(other.intStorage), matrix)
 | 
			
		||||
    }
 | 
			
		||||
    inline operator fun times(other: BlockPointer) : BlockPointer {
 | 
			
		||||
        return BlockPointer(intStorage.times(other.intStorage), matrix)
 | 
			
		||||
    }
 | 
			
		||||
    inline operator fun div(other: BlockPointer) : BlockPointer {
 | 
			
		||||
        return BlockPointer(intStorage.div(other.intStorage), matrix)
 | 
			
		||||
    }
 | 
			
		||||
    inline operator fun rem(other: BlockPointer) : BlockPointer {
 | 
			
		||||
        return BlockPointer(intStorage.rem(other.intStorage), matrix)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    infix fun xorBlocks(other: BlockPointer) : Block {
 | 
			
		||||
        return Block(UByteArray(1024){
 | 
			
		||||
            matrix[this.intStorage + it] xor other.matrix[other.intStorage + it]
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
 | 
			
		||||
inline class Block internal constructor(val storage: UByteArray) : Collection<UByte> {
 | 
			
		||||
    constructor() : this(UByteArray(1024))
 | 
			
		||||
    operator fun get(index: Int) : UByte {
 | 
			
		||||
        return storage.get(index)
 | 
			
		||||
    }
 | 
			
		||||
    operator fun set(index: Int, value: UByte) {
 | 
			
		||||
        storage.set(index, value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val size: Int get() = storage.size
 | 
			
		||||
 | 
			
		||||
    override operator fun iterator(): UByteIterator = Iterator(storage.toByteArray())
 | 
			
		||||
 | 
			
		||||
    private class Iterator(private val array: ByteArray) : UByteIterator() {
 | 
			
		||||
        private var index = 0
 | 
			
		||||
        override fun hasNext() = index < array.size
 | 
			
		||||
        override fun nextUByte() = if (index < array.size) array[index++].toUByte() else throw NoSuchElementException(index.toString())
 | 
			
		||||
    }
 | 
			
		||||
    //Taken from UByteArray implementation
 | 
			
		||||
    override fun contains(element: UByte): Boolean {
 | 
			
		||||
        // TODO: Eliminate this check after KT-30016 gets fixed.
 | 
			
		||||
        // Currently JS BE does not generate special bridge method for this method.
 | 
			
		||||
        if ((element as Any?) !is UByte) return false
 | 
			
		||||
 | 
			
		||||
        return storage.contains(element.toByte())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun containsAll(elements: Collection<UByte>): Boolean {
 | 
			
		||||
        return (elements as Collection<*>).all { it is UByte && storage.contains(it.toByte()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun isEmpty(): Boolean = this.storage.size == 0
 | 
			
		||||
 | 
			
		||||
    fun getRowOfULongsForMixing(rowIndex: Int) : ULongArray {
 | 
			
		||||
        val startOfRow = (rowIndex * 8 * 16)
 | 
			
		||||
 | 
			
		||||
        // Each row has 16 unsigned longs (16 ulongs * 8 bytes = 128 bytes) -- Argon2 considers this as 2 word unsigned
 | 
			
		||||
        // numbers, so strictly speaking argon representation is 8 * 8 matrix of 2 word unsigned numbers (registers
 | 
			
		||||
        val ulongArray = ULongArray(16)
 | 
			
		||||
        for (i in 0 until 16) {
 | 
			
		||||
            var ulong = 0UL
 | 
			
		||||
            //Now we create the ulong
 | 
			
		||||
            for (j in 0 until 8) {
 | 
			
		||||
                ulong = ulong or (storage[startOfRow + i * 8 + j].toULong() shl (j * 8))
 | 
			
		||||
            }
 | 
			
		||||
            ulongArray[i] = ulong
 | 
			
		||||
        }
 | 
			
		||||
        return ulongArray
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    @ExperimentalUnsignedTypes
 | 
			
		||||
        fun ULong.toLittleEndianUByteArray() :UByteArray {
 | 
			
		||||
            return UByteArray (8) {
 | 
			
		||||
                ((this shr (it * 8)) and 0xFFU).toUByte()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    //copy into gblock column
 | 
			
		||||
        for (i in 0..7) {
 | 
			
		||||
            val column = columnData.copyOfRange(i * 16, i * 16 + 16)
 | 
			
		||||
            column.copyInto(gBlock, i * 128 + columnPosition * 16)
 | 
			
		||||
        }
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    fun setRowFromMixedULongs(rowIndex: Int, ulongs: ULongArray) {
 | 
			
		||||
        val startOfRow = (rowIndex * 8 * 16)
 | 
			
		||||
        // Each row has 16 unsigned longs (16 ulongs * 8 bytes = 128 bytes) -- Argon2 considers this as 2 word unsigned
 | 
			
		||||
        // numbers, so strictly speaking argon representation is 8 * 8 matrix of 2 word unsigned numbers (registers
 | 
			
		||||
        for (i in 0 until 16) {
 | 
			
		||||
            val ulongToConvert = ulongs[i]
 | 
			
		||||
            for (j in 0 until 8) {
 | 
			
		||||
                storage[startOfRow + i * 8 + j] = ((ulongToConvert shr (j * 8)) and 0xFFU).toUByte()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
    val result = UByteArray(128) { 0U }
 | 
			
		||||
        for (i in 0..7) {
 | 
			
		||||
            gBlock.copyOfRange(i * 128 + (columnPosition * 16), i * 128 + (columnPosition * 16) + 16)
 | 
			
		||||
                .copyInto(result, i * 16)
 | 
			
		||||
        }
 | 
			
		||||
        return result
 | 
			
		||||
     */
 | 
			
		||||
    fun getColumnOfULongsForMixing(columnIndex: Int) : ULongArray {
 | 
			
		||||
        val ulongArray = ULongArray(16)
 | 
			
		||||
 | 
			
		||||
        for (i in 0 until 16) {
 | 
			
		||||
            var ulong = 0UL
 | 
			
		||||
            //Now we create the ulong
 | 
			
		||||
            for (j in 0 until 8) {
 | 
			
		||||
                ulong = ulong or (storage[i * 128 + columnIndex * 16 + j].toULong() shl (j * 8))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ulongArray
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -111,38 +111,30 @@ object Argon2Utils {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    internal fun allocationlessCompressionFunctionG(
 | 
			
		||||
//        matrix: Argon2Matrix,
 | 
			
		||||
//        previousBlock: BlockPointer,
 | 
			
		||||
//        referenceBlock: BlockPointer,
 | 
			
		||||
//        currentBlock: BlockPointer,
 | 
			
		||||
//        xorWithCurrentBlock: Boolean
 | 
			
		||||
//    ): UByteArray {
 | 
			
		||||
//        val r = referenceBlock xorBlocks previousBlock
 | 
			
		||||
//        val q = Block()
 | 
			
		||||
//        val z = Block()
 | 
			
		||||
//        // Do the argon/blake2b mixing on rows
 | 
			
		||||
//        for (i in 0..7) {
 | 
			
		||||
//            q.setRowFromMixedULongs(i, inplaceMixRound(r.getRowOfULongsForMixing(i)))
 | 
			
		||||
//        }
 | 
			
		||||
//        // Do the argon/blake2b mixing on columns
 | 
			
		||||
//        for (i in 0..7) {
 | 
			
		||||
//            copyIntoGBlockColumn(
 | 
			
		||||
//                z,
 | 
			
		||||
//                i,
 | 
			
		||||
//                mixRound(extractColumnFromGBlock(q, i))
 | 
			
		||||
//                    .map { it.toLittleEndianUByteArray() }
 | 
			
		||||
//                    .flatMap { it.asIterable() }
 | 
			
		||||
//                    .toUByteArray()
 | 
			
		||||
//            )
 | 
			
		||||
//        }
 | 
			
		||||
//        val final = if (xorWithCurrentBlock) {
 | 
			
		||||
//            (z xor r) xor currentBlock
 | 
			
		||||
//        } else {
 | 
			
		||||
//            z xor r
 | 
			
		||||
//        }
 | 
			
		||||
//        return final
 | 
			
		||||
//    }
 | 
			
		||||
    internal fun inplaceCompressionFunctionG(
 | 
			
		||||
        previousBlock: ArgonBlockPointer,
 | 
			
		||||
        referenceBlock: ArgonBlockPointer,
 | 
			
		||||
        currentBlock: ArgonBlockPointer,
 | 
			
		||||
        xorWithCurrentBlock: Boolean
 | 
			
		||||
    ): ArgonBlockPointer {
 | 
			
		||||
        val r = (referenceBlock xorBlocksAndGetPointerToNewBlock previousBlock).getBlockPointer()
 | 
			
		||||
        val q = ArgonBlock().getBlockPointer()
 | 
			
		||||
        val z = ArgonBlock().getBlockPointer()
 | 
			
		||||
        // Do the argon/blake2b mixing on rows
 | 
			
		||||
        for (i in 0..7) {
 | 
			
		||||
            q.setRowFromMixedULongs(i, inplaceMixRound(r.getRowOfULongsForMixing(i)))
 | 
			
		||||
        }
 | 
			
		||||
        // Do the argon/blake2b mixing on columns
 | 
			
		||||
        for (i in 0..7) {
 | 
			
		||||
            z.setColumnFromMixedULongs(i, inplaceMixRound(q.getColumnOfULongsForMixing(i)))
 | 
			
		||||
        }
 | 
			
		||||
        val final = if (xorWithCurrentBlock) {
 | 
			
		||||
            (z xorInplace r) xorInplace  currentBlock
 | 
			
		||||
        } else {
 | 
			
		||||
            z xorInplace r
 | 
			
		||||
        }
 | 
			
		||||
        return final
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal fun compressionFunctionG(
 | 
			
		||||
        previousBlock: UByteArray,
 | 
			
		||||
@ -249,6 +241,6 @@ object Argon2Utils {
 | 
			
		||||
// ------------ Arithmetic and other utils
 | 
			
		||||
 | 
			
		||||
@ExperimentalUnsignedTypes
 | 
			
		||||
fun UByteArray.xorWithBlock(other : Argon2Matrix, rowPosition: Int, columnPosition: Int) : UByteArray {
 | 
			
		||||
fun UByteArray.xorWithBlock(other : ArgonMatrix, rowPosition: Int, columnPosition: Int) : UByteArray {
 | 
			
		||||
    return UByteArray(BLOCK_SIZE) { this[it] xor other[rowPosition, columnPosition, it] }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,279 @@
 | 
			
		||||
/*
 | 
			
		||||
 *    Copyright 2019 Ugljesa Jovanovic
 | 
			
		||||
 *
 | 
			
		||||
 *    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 *    you may not use this file except in compliance with the License.
 | 
			
		||||
 *    You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 *    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 *    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 *    See the License for the specific language governing permissions and
 | 
			
		||||
 *    limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
 | 
			
		||||
 | 
			
		||||
package com.ionspin.kotlin.crypto.keyderivation.argon2
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a pointer to a Argon2 Block, this abstracts what the backing structure is, a Argon 2 Matrix or
 | 
			
		||||
 * or a UByteArray block
 | 
			
		||||
 */
 | 
			
		||||
interface ArgonBlockPointer {
 | 
			
		||||
    val blockStartPosition: Int
 | 
			
		||||
 | 
			
		||||
    fun pointerArithmetic(block : (Int, Int) -> Int) : ArgonBlockPointer
 | 
			
		||||
 | 
			
		||||
    infix fun xorBlocksAndGetPointerToNewBlock(other: ArgonBlockPointer) : ArgonBlock
 | 
			
		||||
 | 
			
		||||
    operator fun get(blockPosition: Int) : UByte
 | 
			
		||||
 | 
			
		||||
    operator fun set(blockPosition: Int, value: UByte)
 | 
			
		||||
 | 
			
		||||
    infix fun xorInplace(other: ArgonBlockPointer) : ArgonBlockPointer {
 | 
			
		||||
        (0 until 1024).forEach {
 | 
			
		||||
            this[it] = this[it] xor other[it]
 | 
			
		||||
        }
 | 
			
		||||
        return this //For chaining
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun asInt() : Int
 | 
			
		||||
 | 
			
		||||
    fun getAsUByteArray() : UByteArray
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun ArgonBlockPointer.getRowOfULongsForMixing(rowIndex: Int) : ULongArray {
 | 
			
		||||
    // Each row has 16 unsigned longs (16 ulongs * 8 bytes = 128 bytes) -- Argon2 considers this as 2 word unsigned
 | 
			
		||||
    // numbers, so strictly speaking argon representation is 8 * 8 matrix of 2 word unsigned numbers (registers
 | 
			
		||||
    val ulongArray = ULongArray(16)
 | 
			
		||||
    for (columnIndex in 0 until 16) {
 | 
			
		||||
        var ulong = 0UL
 | 
			
		||||
        //Now we create the ulong
 | 
			
		||||
        for (bytePosition in 0 until 8) {
 | 
			
		||||
            ulong = ulong or (this[rowIndex * 128 + columnIndex * 8 + bytePosition].toULong() shl (bytePosition * 8))
 | 
			
		||||
        }
 | 
			
		||||
        ulongArray[columnIndex] = ulong
 | 
			
		||||
    }
 | 
			
		||||
    return ulongArray
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun ArgonBlockPointer.setRowFromMixedULongs(rowIndex: Int, ulongs: ULongArray) {
 | 
			
		||||
    // Each row has 16 unsigned longs (16 ulongs * 8 bytes = 128 bytes) -- Argon2 considers this as 2 word unsigned
 | 
			
		||||
    // numbers, so strictly speaking argon representation is 8 * 8 matrix of 2 word unsigned numbers (registers
 | 
			
		||||
    for (columnIndex in 0 until 16) {
 | 
			
		||||
        val ulongToConvert = ulongs[columnIndex]
 | 
			
		||||
        for (bytePosition in 0 until 8) {
 | 
			
		||||
            this[rowIndex * 128 + columnIndex * 8 + bytePosition] = ((ulongToConvert shr (bytePosition * 8)) and 0xFFU).toUByte()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun ArgonBlockPointer.getColumnOfULongsForMixing(columnIndex: Int) : ULongArray {
 | 
			
		||||
    //In Argon2 representation there are 8 double word registers (numbers, but we work with 16 single word ulongs
 | 
			
		||||
    val ulongArray = ULongArray(16)
 | 
			
		||||
    //There are 8 rows that consist of 2 words (registers, in our case ulongs) each
 | 
			
		||||
    for (rowIndex in 0 until 8) {
 | 
			
		||||
        var ulong = 0UL
 | 
			
		||||
        //Now we create the ulong
 | 
			
		||||
        for (bytePosition in 0 until 8) {
 | 
			
		||||
            ulong = ulong or (this[rowIndex * 128 + columnIndex * 16 + bytePosition].toULong() shl (bytePosition * 8))
 | 
			
		||||
        }
 | 
			
		||||
        ulongArray[rowIndex * 2] = ulong
 | 
			
		||||
        ulong = 0UL
 | 
			
		||||
        // But unlike in columns where we can directly iterate and get all TWO WORD registers, here we also need to grab
 | 
			
		||||
        // the next word
 | 
			
		||||
        for (bytePosition in 8 until 16) {
 | 
			
		||||
            ulong = ulong or (this[rowIndex * 128 + columnIndex * 16 + bytePosition].toULong() shl (bytePosition * 8))
 | 
			
		||||
        }
 | 
			
		||||
        ulongArray[rowIndex * 2 + 1] = ulong
 | 
			
		||||
    }
 | 
			
		||||
    return ulongArray
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun ArgonBlockPointer.setColumnFromMixedULongs(columnIndex: Int, ulongs: ULongArray)  {
 | 
			
		||||
    //In Argon2 representation there are 8 double word registers (numbers, but we work with 16 single word ulongs
 | 
			
		||||
    //There are 8 rows that consist of 2 words (registers, in our case ulongs) each
 | 
			
		||||
    var ulongToConvert = 0UL
 | 
			
		||||
    for (rowIndex in 0 until 8) {
 | 
			
		||||
        ulongToConvert = ulongs[rowIndex * 2]
 | 
			
		||||
        //Now we create the ulong
 | 
			
		||||
        for (bytePosition in 0 until 8) {
 | 
			
		||||
            this[rowIndex * 128 + columnIndex * 16 + bytePosition] = ((ulongToConvert shr (bytePosition * 8)) and 0xFFU).toUByte()
 | 
			
		||||
        }
 | 
			
		||||
        // But unlike in columns where we can directly iterate and get all TWO WORD registers, here we also need to set
 | 
			
		||||
        // the next word
 | 
			
		||||
        ulongToConvert = ulongs[rowIndex * 2 + 1]
 | 
			
		||||
        for (bytePosition in 8 until 16) {
 | 
			
		||||
            this[rowIndex * 128 + columnIndex * 16 + bytePosition] = ((ulongToConvert shr (bytePosition * 8)) and 0xFFU).toUByte()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun ArgonBlockPointer.getUIntFromPosition(positionInBlock: Int) : UInt {
 | 
			
		||||
    var uint = 0U
 | 
			
		||||
    for (i in 0 until 4) {
 | 
			
		||||
        uint = uint or (this[positionInBlock + i].toUInt() shl (i * 8))
 | 
			
		||||
    }
 | 
			
		||||
    return uint
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by Ugljesa Jovanovic
 | 
			
		||||
 * ugljesa.jovanovic@ionspin.com
 | 
			
		||||
 * on 21-May-2020
 | 
			
		||||
 */
 | 
			
		||||
 class ArgonMatrix(val columnCount: Int, val rowCount: Int) {
 | 
			
		||||
 | 
			
		||||
    internal val storage: UByteArray = UByteArray(columnCount * rowCount * 1024)
 | 
			
		||||
 | 
			
		||||
    operator fun get(rowPosition: Int, columnPosition: Int, inBlockPosition: Int) : UByte {
 | 
			
		||||
        if (rowPosition > rowCount - 1) {
 | 
			
		||||
            throw RuntimeException("Invalid row (lane) requested: $rowPosition, rowCount: $rowCount")
 | 
			
		||||
        }
 | 
			
		||||
        if (columnPosition > columnCount - 1) {
 | 
			
		||||
            throw RuntimeException("Invalid column requested: $columnPosition, columnCount: $columnCount")
 | 
			
		||||
        }
 | 
			
		||||
        return storage[getBlockStartPositionPointer(rowPosition, columnPosition) + inBlockPosition]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val size = storage.size
 | 
			
		||||
 | 
			
		||||
    operator fun get(absolutePosition: Int) : UByte {
 | 
			
		||||
        return storage[absolutePosition]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    operator fun set(rowPosition: Int, columnPosition: Int, inBlockPosition: Int, value: UByte) {
 | 
			
		||||
        storage[getBlockStartPositionPointer(rowPosition, columnPosition) + inBlockPosition] = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    operator fun set(absolutePosition: Int, value: UByte) {
 | 
			
		||||
        storage[absolutePosition] = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getBlockPointer(rowPosition: Int, columnPosition: Int) : ArgonBlockPointer {
 | 
			
		||||
        return ArgonBlockPointerWithMatrix(getBlockStartPositionPointer(rowPosition, columnPosition), this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun sliceArray(indices: IntRange): UByteArray {
 | 
			
		||||
        return storage.sliceArray(indices)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getBlockAt(rowPosition: Int, columnPosition: Int) : UByteArray {
 | 
			
		||||
                println("Expensive get")
 | 
			
		||||
        return storage.copyOfRange(
 | 
			
		||||
            getBlockStartPositionPointer(rowPosition, columnPosition),
 | 
			
		||||
            getBlockStartPositionPointer(rowPosition, columnPosition) + 1024
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) {
 | 
			
		||||
        println("Expensive set")
 | 
			
		||||
        blockValue.copyInto(
 | 
			
		||||
            storage,
 | 
			
		||||
            getBlockStartPositionPointer(rowPosition, columnPosition)
 | 
			
		||||
            )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private inline fun getBlockStartPositionPointer(rowPosition: Int, columnPosition: Int) : Int {
 | 
			
		||||
        return rowPosition * columnCount * 1024 + columnPosition * 1024
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal fun clearMatrix() {
 | 
			
		||||
        for( index in storage.indices) { storage[index] = 0U }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class ArgonBlockPointerWithMatrix constructor(override val blockStartPosition: Int, val matrix: ArgonMatrix) : ArgonBlockPointer {
 | 
			
		||||
 | 
			
		||||
        override fun pointerArithmetic(block: (Int, Int) -> Int): ArgonBlockPointer {
 | 
			
		||||
            return ArgonBlockPointerWithMatrix(block(blockStartPosition, matrix.size), matrix)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun asInt(): Int {
 | 
			
		||||
            return blockStartPosition
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override operator fun get(blockPosition: Int) : UByte {
 | 
			
		||||
            return matrix[blockStartPosition + blockPosition]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun set(blockPosition: Int, value: UByte) {
 | 
			
		||||
            matrix[blockStartPosition + blockPosition] = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override infix fun xorBlocksAndGetPointerToNewBlock(other: ArgonBlockPointer) : ArgonBlock {
 | 
			
		||||
            return ArgonBlock(UByteArray(1024){
 | 
			
		||||
                matrix[blockStartPosition + it] xor other[it]
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun getAsUByteArray(): UByteArray {
 | 
			
		||||
            return matrix.storage.slice(blockStartPosition until blockStartPosition + 1024).toUByteArray()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
 | 
			
		||||
inline class ArgonBlock internal constructor(internal val storage: UByteArray) {
 | 
			
		||||
    constructor() : this(UByteArray(1024))
 | 
			
		||||
    operator fun get(index: Int) : UByte {
 | 
			
		||||
        return storage.get(index)
 | 
			
		||||
    }
 | 
			
		||||
    operator fun set(index: Int, value: UByte) {
 | 
			
		||||
        storage.set(index, value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val size: Int get() = storage.size
 | 
			
		||||
 | 
			
		||||
    internal fun getAsUByteArray() : UByteArray = storage
 | 
			
		||||
 | 
			
		||||
    fun getBlockPointer() : ArgonBlockPointer{
 | 
			
		||||
        return ArgonBlockPointerWithBlock( this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    infix fun xorInplace(other: ArgonBlock) : ArgonBlock {
 | 
			
		||||
        storage.indices.forEach {
 | 
			
		||||
            this[it] = this[it] xor other[it]
 | 
			
		||||
        }
 | 
			
		||||
        return this //For chaining
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private class ArgonBlockPointerWithBlock constructor(val storageBlock: ArgonBlock) : ArgonBlockPointer {
 | 
			
		||||
        override val blockStartPosition: Int = 0
 | 
			
		||||
 | 
			
		||||
        override fun pointerArithmetic(block: (Int, Int) -> Int): ArgonBlockPointer {
 | 
			
		||||
            throw RuntimeException("Haven't really tought out pointer arithmetic with blocks")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun asInt(): Int {
 | 
			
		||||
            return blockStartPosition
 | 
			
		||||
        }
 | 
			
		||||
        override operator fun get(blockPosition: Int) : UByte {
 | 
			
		||||
            return storageBlock[blockPosition]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun set(blockPosition: Int, value: UByte) {
 | 
			
		||||
            storageBlock[blockPosition] = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override infix fun xorBlocksAndGetPointerToNewBlock(other: ArgonBlockPointer) : ArgonBlock {
 | 
			
		||||
            return ArgonBlock(UByteArray(1024){
 | 
			
		||||
                storageBlock[it] xor other[it]
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun getAsUByteArray(): UByteArray {
 | 
			
		||||
            return storageBlock.storage.slice(blockStartPosition until blockStartPosition + 1024).toUByteArray()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -18,9 +18,7 @@
 | 
			
		||||
 | 
			
		||||
package com.ionspin.kotlin.crypto.hash.argon
 | 
			
		||||
 | 
			
		||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Matrix
 | 
			
		||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils
 | 
			
		||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Block
 | 
			
		||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.*
 | 
			
		||||
import com.ionspin.kotlin.crypto.util.arrayChunked
 | 
			
		||||
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong
 | 
			
		||||
import kotlin.random.Random
 | 
			
		||||
@ -45,7 +43,7 @@ class Argon2MatrixTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun indexAccessTest() {
 | 
			
		||||
        val argon2Matrix = Argon2Matrix(2, 2)
 | 
			
		||||
        val argon2Matrix = ArgonMatrix(2, 2)
 | 
			
		||||
        (zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage)
 | 
			
		||||
        println(argon2Matrix[0, 0, 0])
 | 
			
		||||
        println(argon2Matrix[0, 1, 0])
 | 
			
		||||
@ -74,7 +72,7 @@ class Argon2MatrixTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun blockRetrievalTest() {
 | 
			
		||||
        val argon2Matrix = Argon2Matrix(2, 2)
 | 
			
		||||
        val argon2Matrix = ArgonMatrix(2, 2)
 | 
			
		||||
        (zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage)
 | 
			
		||||
        assertTrue {
 | 
			
		||||
            zeroesBlock.contentEquals(argon2Matrix.getBlockAt(0, 0)) &&
 | 
			
		||||
@ -86,14 +84,14 @@ class Argon2MatrixTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun blockColumnToUlongTest() {
 | 
			
		||||
        val randomBlock = Block(randomBlockArray)
 | 
			
		||||
        val randomBlock = ArgonBlock(randomBlockArray)
 | 
			
		||||
        for (columnIndex in 0 until 8) {
 | 
			
		||||
            val startOfRow = (columnIndex * 8 * 16)
 | 
			
		||||
            val endOfRow = startOfRow + (8 * 16)
 | 
			
		||||
            val rowToMix = randomBlockArray.copyOfRange(startOfRow, endOfRow)
 | 
			
		||||
            val expected = rowToMix.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toULongArray()
 | 
			
		||||
 | 
			
		||||
            val result = randomBlock.getRowOfULongsForMixing(columnIndex)
 | 
			
		||||
            val result = randomBlock.getBlockPointer().getRowOfULongsForMixing(columnIndex)
 | 
			
		||||
 | 
			
		||||
            assertTrue { expected.contentEquals(result) }
 | 
			
		||||
        }
 | 
			
		||||
@ -101,12 +99,44 @@ class Argon2MatrixTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun blockRowToULongTest() {
 | 
			
		||||
        val randomBlock = Block(randomBlockArray)
 | 
			
		||||
        val columnToMix = Argon2Utils.extractColumnFromGBlock(randomBlockArray, 0)
 | 
			
		||||
        val expected = columnToMix.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toULongArray()
 | 
			
		||||
        val result = randomBlock.getColumnOfULongsForMixing(0)
 | 
			
		||||
        val randomBlock = ArgonBlock(randomBlockArray)
 | 
			
		||||
        for (rowIndex in 0 until 8) {
 | 
			
		||||
            val columnToMix = Argon2Utils.extractColumnFromGBlock(randomBlockArray, rowIndex)
 | 
			
		||||
            val expected = columnToMix.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toULongArray()
 | 
			
		||||
            val result = randomBlock.getBlockPointer().getColumnOfULongsForMixing(rowIndex)
 | 
			
		||||
 | 
			
		||||
        assertTrue { expected.contentEquals(result) }
 | 
			
		||||
            assertTrue { expected.contentEquals(result) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun blockSetMixedRowTest() {
 | 
			
		||||
        val randomBlock = ArgonBlock(randomBlockArray)
 | 
			
		||||
        val targetBlockArray = zeroesBlock.copyOf()
 | 
			
		||||
        val targetBlock = ArgonBlock(targetBlockArray)
 | 
			
		||||
        for (rowIndex in 0 until 8) {
 | 
			
		||||
            val extracted = randomBlock.getBlockPointer().getRowOfULongsForMixing(rowIndex)
 | 
			
		||||
            targetBlock.getBlockPointer().setRowFromMixedULongs(rowIndex, extracted)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assertTrue {
 | 
			
		||||
            randomBlockArray.contentEquals(targetBlock.storage)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun blockSetMixedColumnTest() {
 | 
			
		||||
        val randomBlock = ArgonBlock(randomBlockArray)
 | 
			
		||||
        val targetBlockArray = zeroesBlock.copyOf()
 | 
			
		||||
        val targetBlock = ArgonBlock(targetBlockArray)
 | 
			
		||||
        for (columnIndex in 0 until 8) {
 | 
			
		||||
            val extracted = randomBlock.getBlockPointer().getColumnOfULongsForMixing(columnIndex)
 | 
			
		||||
            targetBlock.getBlockPointer().setColumnFromMixedULongs(columnIndex, extracted)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assertTrue {
 | 
			
		||||
            randomBlockArray.contentEquals(targetBlock.storage)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user