Rename and cleanup of accidentally added node-modules
This commit is contained in:
600 files changed
+6
-297309
No files matched your search
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* 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("UnstableApiUsage")
|
||||
|
||||
import com.moowork.gradle.node.task.NodeTask
|
||||
import org.gradle.api.tasks.testing.logging.TestLogging
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
|
||||
plugins {
|
||||
kotlin(PluginsDeps.multiplatform)
|
||||
id (PluginsDeps.mavenPublish)
|
||||
id (PluginsDeps.signing)
|
||||
id (PluginsDeps.node) version Versions.nodePlugin
|
||||
id (PluginsDeps.dokka) version Versions.dokkaPlugin
|
||||
}
|
||||
|
||||
val sonatypeStaging = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||
val sonatypeSnapshots = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
|
||||
val sonatypePassword : String? by project
|
||||
|
||||
val sonatypeUsername : String? by project
|
||||
|
||||
val sonatypePasswordEnv : String? = System.getenv()["SONATYPE_PASSWORD"]
|
||||
val sonatypeUsernameEnv : String? = System.getenv()["SONATYPE_USERNAME"]
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
group = "com.ionspin.kotlin"
|
||||
version = "0.1.0-SNAPSHOT"
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
js {
|
||||
compilations {
|
||||
this.forEach {
|
||||
it.compileKotlinTask.kotlinOptions.sourceMap = true
|
||||
it.compileKotlinTask.kotlinOptions.moduleKind = "commonjs"
|
||||
it.compileKotlinTask.kotlinOptions.metaInfo = true
|
||||
|
||||
if (it.name == "main") {
|
||||
it.compileKotlinTask.kotlinOptions.main = "call"
|
||||
}
|
||||
println("Compilation name ${it.name} set")
|
||||
println("Destination dir ${it.compileKotlinTask.destinationDir}")
|
||||
}
|
||||
}
|
||||
}
|
||||
linuxX64("linux") {
|
||||
binaries {
|
||||
staticLib {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
iosX64("ios") {
|
||||
binaries {
|
||||
framework {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
iosArm64("ios64Arm") {
|
||||
binaries {
|
||||
framework {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iosArm32("ios32Arm") {
|
||||
binaries {
|
||||
framework {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
macosX64() {
|
||||
binaries {
|
||||
framework {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println(targets.names)
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin(Deps.Common.stdLib))
|
||||
implementation(kotlin(Deps.Common.test))
|
||||
implementation(Deps.Common.coroutines)
|
||||
implementation(Deps.Common.kotlinBigNum)
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin(Deps.Common.test))
|
||||
implementation(kotlin(Deps.Common.testAnnotation))
|
||||
}
|
||||
}
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin(Deps.Jvm.stdLib))
|
||||
implementation(kotlin(Deps.Jvm.test))
|
||||
implementation(kotlin(Deps.Jvm.testJUnit))
|
||||
implementation(Deps.Jvm.coroutinesCore)
|
||||
}
|
||||
}
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin(Deps.Jvm.test))
|
||||
implementation(kotlin(Deps.Jvm.testJUnit))
|
||||
implementation(Deps.Jvm.oshi)
|
||||
implementation(Deps.Jvm.coroutinesTest)
|
||||
implementation(kotlin(Deps.Jvm.reflection))
|
||||
}
|
||||
}
|
||||
val jsMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin(Deps.Js.stdLib))
|
||||
implementation(kotlin(Deps.Js.test))
|
||||
implementation(Deps.Js.coroutines)
|
||||
}
|
||||
}
|
||||
val jsTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test-js"))
|
||||
}
|
||||
}
|
||||
val nativeMain by creating {
|
||||
dependsOn(commonMain)
|
||||
dependencies {
|
||||
implementation(Deps.Native.coroutines)
|
||||
}
|
||||
}
|
||||
val nativeTest by creating {
|
||||
|
||||
}
|
||||
|
||||
val iosMain by getting {
|
||||
dependsOn(nativeMain)
|
||||
}
|
||||
val iosTest by getting {
|
||||
dependsOn(nativeTest)
|
||||
}
|
||||
|
||||
val ios64ArmMain by getting {
|
||||
dependsOn(nativeMain)
|
||||
}
|
||||
val ios64ArmTest by getting {
|
||||
dependsOn(nativeTest)
|
||||
}
|
||||
|
||||
val ios32ArmMain by getting {
|
||||
dependsOn(nativeMain)
|
||||
}
|
||||
val ios32ArmTest by getting {
|
||||
dependsOn(nativeTest)
|
||||
}
|
||||
|
||||
val macosX64Main by getting {
|
||||
dependsOn(nativeMain)
|
||||
}
|
||||
val macosX64Test by getting {
|
||||
dependsOn(nativeTest)
|
||||
}
|
||||
val linuxMain by getting {
|
||||
dependsOn(nativeMain)
|
||||
}
|
||||
val linuxTest by getting {
|
||||
dependsOn(nativeTest)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
task<Copy>("copyPackageJson") {
|
||||
dependsOn("compileKotlinJs")
|
||||
println("Copying package.json from $projectDir/core/src/jsMain/npm")
|
||||
from ("$projectDir/src/jsMain/npm")
|
||||
println("Node modules dir ${node.nodeModulesDir}")
|
||||
into ("${node.nodeModulesDir}")
|
||||
}
|
||||
|
||||
tasks {
|
||||
val npmInstall by getting
|
||||
val compileKotlinJs by getting(AbstractCompile::class)
|
||||
val compileTestKotlinJs by getting(Kotlin2JsCompile::class)
|
||||
val jsTest by getting
|
||||
|
||||
|
||||
val populateNodeModulesForTests by creating {
|
||||
dependsOn(npmInstall, compileKotlinJs, compileTestKotlinJs)
|
||||
doLast {
|
||||
copy {
|
||||
from(compileKotlinJs.destinationDir)
|
||||
configurations["jsRuntimeClasspath"].forEach {
|
||||
from(zipTree(it.absolutePath).matching { include("*.js") })
|
||||
}
|
||||
configurations["jsTestRuntimeClasspath"].forEach {
|
||||
from(zipTree(it.absolutePath).matching { include("*.js") })
|
||||
}
|
||||
|
||||
into("$projectDir/node_modules")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val runTestsWithMocha by creating(NodeTask::class) {
|
||||
dependsOn(populateNodeModulesForTests)
|
||||
setScript(file("$projectDir/node_modules/mocha/bin/mocha"))
|
||||
setArgs(listOf(
|
||||
compileTestKotlinJs.outputFile,
|
||||
"--reporter-options",
|
||||
"topLevelSuite=${project.name}-tests"
|
||||
))
|
||||
}
|
||||
|
||||
jsTest.dependsOn("copyPackageJson")
|
||||
jsTest.dependsOn(runTestsWithMocha)
|
||||
|
||||
create<Jar>("javadocJar") {
|
||||
dependsOn(dokka)
|
||||
archiveClassifier.set("javadoc")
|
||||
from(dokka.get().outputDirectory)
|
||||
}
|
||||
|
||||
dokka {
|
||||
println ("Dokka !")
|
||||
impliedPlatforms = mutableListOf("Common")
|
||||
kotlinTasks {
|
||||
listOf()
|
||||
}
|
||||
sourceRoot {
|
||||
println ("Common !")
|
||||
path = "/home/ionspin/Projects/Future/kotlin-multiplatform-crypto/crypto/src/commonMain" //TODO remove static path!
|
||||
platforms = listOf("Common")
|
||||
}
|
||||
}
|
||||
|
||||
val jvmTest by getting(Test::class) {
|
||||
testLogging {
|
||||
events("PASSED", "FAILED", "SKIPPED")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
signing {
|
||||
isRequired = false
|
||||
sign(publishing.publications)
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.withType(MavenPublication::class) {
|
||||
artifact(tasks["javadocJar"])
|
||||
pom {
|
||||
name.set("Kotlin Multiplatform Crypto")
|
||||
description.set("Kotlin Multiplatform Crypto library")
|
||||
url.set("https://github.com/ionspin/kotlin-multiplatform-crypto")
|
||||
licenses {
|
||||
license {
|
||||
name.set("The Apache License, Version 2.0")
|
||||
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id.set("ionspin")
|
||||
name.set("Ugljesa Jovanovic")
|
||||
email.set("opensource@ionspin.com")
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url.set("https://github.com/ionspin/kotlin-multiplatform-crypto")
|
||||
connection.set("scm:git:git://git@github.com:ionspin/kotlin-multiplatform-crypto.git")
|
||||
developerConnection.set("scm:git:ssh://git@github.com:ionspin/kotlin-multiplatform-crypto.git")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
|
||||
url = uri(sonatypeStaging)
|
||||
credentials {
|
||||
username = sonatypeUsername ?: sonatypeUsernameEnv ?: ""
|
||||
password = sonatypePassword ?: sonatypePasswordEnv ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "snapshot"
|
||||
url = uri(sonatypeSnapshots)
|
||||
credentials {
|
||||
username = sonatypeUsername ?: sonatypeUsernameEnv ?: ""
|
||||
password = sonatypePassword ?: sonatypePasswordEnv ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
object Config {
|
||||
const val DEBUG = false
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
interface Hash
|
||||
|
||||
interface UpdateableHash : Hash
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 15-Jul-2019
|
||||
*/
|
||||
fun Array<Byte>.hexColumsPrint() {
|
||||
val printout = this.map { it.toString(16) }.chunked(16)
|
||||
printout.forEach { println(it.joinToString(separator = " ") { it.toUpperCase() }) }
|
||||
}
|
||||
|
||||
fun Array<UByte>.hexColumsPrint() {
|
||||
val printout = this.map { it.toString(16) }.chunked(16)
|
||||
printout.forEach { println(it.joinToString(separator = " ") { it.toUpperCase() }) }
|
||||
}
|
||||
|
||||
fun Array<ULong>.hexColumsPrint() {
|
||||
val printout = this.map { it.toString(16) }.chunked(3)
|
||||
printout.forEach { println(it.joinToString(separator = " ") { it.toUpperCase() }) }
|
||||
}
|
||||
|
||||
inline fun <reified T> Array<T>.chunked(sliceSize: Int): Array<Array<T>> {
|
||||
val last = this.size % sliceSize
|
||||
val hasLast = last != 0
|
||||
val numberOfSlices = this.size / sliceSize
|
||||
|
||||
|
||||
val result : MutableList<List<T>> = MutableList<List<T>>(0) { emptyList() }
|
||||
|
||||
for (i in 0 until numberOfSlices) {
|
||||
result.add(this.slice(i * sliceSize until (i + 1) * sliceSize))
|
||||
}
|
||||
if (hasLast) {
|
||||
result.add(this.slice(numberOfSlices * sliceSize until this.size))
|
||||
}
|
||||
|
||||
return result.map { it.toTypedArray() }.toTypedArray()
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
infix fun UInt.rotateRight(places: Int): UInt {
|
||||
return (this shr places) xor (this shl (32 - places))
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
infix fun ULong.rotateRight(places: Int): ULong {
|
||||
return (this shr places) xor (this shl (64 - places))
|
||||
}
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.blake2b
|
||||
|
||||
import com.ionspin.kotlin.bignum.integer.BigInteger
|
||||
import com.ionspin.kotlin.bignum.integer.toBigInteger
|
||||
import com.ionspin.kotlin.crypto.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 14-Jul-2019
|
||||
*/
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class Blake2b(val key: Array<UByte>? = null, val hashLength: Int = 64) : UpdateableHash {
|
||||
companion object : Hash {
|
||||
|
||||
const val BITS_IN_WORD = 64
|
||||
const val ROUNDS_IN_COMPRESS = 12
|
||||
const val BLOCK_BYTES = 128
|
||||
const val MAX_HASH_BYTES = 64
|
||||
const val MIN_HASH_BYTES = 1
|
||||
const val MAX_KEY_BYTES = 64
|
||||
const val MIN_KEY_BYTES = 0
|
||||
val MAX_INPUT_BYTES = 2.toBigInteger() shl 128
|
||||
|
||||
private val sigma = arrayOf(
|
||||
arrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||
arrayOf(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3),
|
||||
arrayOf(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4),
|
||||
arrayOf(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8),
|
||||
arrayOf(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13),
|
||||
arrayOf(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9),
|
||||
arrayOf(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11),
|
||||
arrayOf(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10),
|
||||
arrayOf(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5),
|
||||
arrayOf(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0)
|
||||
)
|
||||
|
||||
|
||||
private val iv = arrayOf(
|
||||
0X6A09E667F3BCC908UL,
|
||||
0XBB67AE8584CAA73BUL,
|
||||
0X3C6EF372FE94F82BUL,
|
||||
0XA54FF53A5F1D36F1UL,
|
||||
0X510E527FADE682D1UL,
|
||||
0X9B05688C2B3E6C1FUL,
|
||||
0X1F83D9ABFB41BD6BUL,
|
||||
0X5BE0CD19137E2179UL
|
||||
)
|
||||
|
||||
const val R1 = 32
|
||||
const val R2 = 24
|
||||
const val R3 = 16
|
||||
const val R4 = 63
|
||||
|
||||
internal fun mixRound(input: Array<ULong>, message: Array<ULong>, round: Int): Array<ULong> {
|
||||
var v = input
|
||||
val selectedSigma = sigma[round % 10]
|
||||
v = mix(v, 0, 4, 8, 12, message[selectedSigma[0]], message[selectedSigma[1]])
|
||||
v = mix(v, 1, 5, 9, 13, message[selectedSigma[2]], message[selectedSigma[3]])
|
||||
v = mix(v, 2, 6, 10, 14, message[selectedSigma[4]], message[selectedSigma[5]])
|
||||
v = mix(v, 3, 7, 11, 15, message[selectedSigma[6]], message[selectedSigma[7]])
|
||||
v = mix(v, 0, 5, 10, 15, message[selectedSigma[8]], message[selectedSigma[9]])
|
||||
v = mix(v, 1, 6, 11, 12, message[selectedSigma[10]], message[selectedSigma[11]])
|
||||
v = mix(v, 2, 7, 8, 13, message[selectedSigma[12]], message[selectedSigma[13]])
|
||||
v = mix(v, 3, 4, 9, 14, message[selectedSigma[14]], message[selectedSigma[15]])
|
||||
return v
|
||||
|
||||
}
|
||||
|
||||
private fun mix(v: Array<ULong>, a: Int, b: Int, c: Int, d: Int, x: ULong, y: ULong): Array<ULong> {
|
||||
v[a] = (v[a] + v[b] + x)
|
||||
v[d] = (v[d] xor v[a]) rotateRight R1
|
||||
v[c] = (v[c] + v[d])
|
||||
v[b] = (v[b] xor v[c]) rotateRight R2
|
||||
v[a] = (v[a] + v[b] + y)
|
||||
v[d] = (v[d] xor v[a]) rotateRight R3
|
||||
v[c] = (v[c] + v[d])
|
||||
v[b] = (v[b] xor v[c]) rotateRight R4
|
||||
return v
|
||||
}
|
||||
|
||||
fun compress(
|
||||
h: Array<ULong>,
|
||||
input: Array<UByte>,
|
||||
offsetCounter: BigInteger,
|
||||
finalBlock: Boolean
|
||||
): Array<ULong> {
|
||||
var v = Array(16) {
|
||||
when (it) {
|
||||
in 0..7 -> h[it]
|
||||
else -> iv[it - 8]
|
||||
}
|
||||
}
|
||||
|
||||
val m = input.foldIndexed(Array(16) { 0UL }) { index, acc, byte ->
|
||||
val slot = index / 8
|
||||
val position = index % 8
|
||||
acc[slot] = acc[slot] + (byte.toULong() shl ((position) * 8))
|
||||
acc
|
||||
}
|
||||
if (Config.DEBUG) {
|
||||
val printout = m.map { it.toString(16) }.chunked(4)
|
||||
printout.forEach { println(it.joinToString(separator = " ") { it.toUpperCase() }) }
|
||||
println("Offset ${offsetCounter}")
|
||||
}
|
||||
|
||||
v[12] = v[12] xor offsetCounter.ulongValue()
|
||||
v[13] = v[13] xor (offsetCounter shr BITS_IN_WORD).ulongValue()
|
||||
|
||||
if (finalBlock) {
|
||||
// v[14] = v[14] xor 0xFFFFFFFFFFFFFFFFUL
|
||||
v[14] = v[14].inv()
|
||||
}
|
||||
|
||||
for (i in 0 until ROUNDS_IN_COMPRESS) {
|
||||
mixRound(v, m, i)
|
||||
}
|
||||
|
||||
for (i in 0..7) {
|
||||
h[i] = h[i] xor v[i] xor v[i + 8]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun digest(inputString: String, key: String? = null): Array<UByte> {
|
||||
val chunked = inputString.encodeToByteArray().map { it.toUByte() }.toList().chunked(BLOCK_BYTES)
|
||||
.map { it.toTypedArray() }.toTypedArray()
|
||||
val keyBytes = key?.run {
|
||||
encodeToByteArray().map { it.toUByte() }.toTypedArray()
|
||||
} ?: emptyArray()
|
||||
return digest(inputMessage = chunked, secretKey = keyBytes)
|
||||
|
||||
}
|
||||
|
||||
fun digest(
|
||||
inputMessage: Array<Array<UByte>> = emptyArray(),
|
||||
secretKey: Array<UByte> = emptyArray(),
|
||||
hashLength: Int = MAX_HASH_BYTES
|
||||
): Array<UByte> {
|
||||
val h = iv.copyOf()
|
||||
|
||||
h[0] = h[0] xor 0x01010000UL xor (secretKey.size.toULong() shl 8) xor hashLength.toULong()
|
||||
|
||||
|
||||
val message = if (secretKey.isEmpty()) {
|
||||
if (inputMessage.isEmpty()) {
|
||||
Array(1) {
|
||||
Array<UByte>(128) {
|
||||
0U
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inputMessage
|
||||
}
|
||||
} else {
|
||||
arrayOf(padToBlock(secretKey), *inputMessage)
|
||||
}
|
||||
|
||||
if (message.size > 1) {
|
||||
for (i in 0 until message.size - 1) {
|
||||
compress(h, message[i], ((i + 1) * BLOCK_BYTES).toBigInteger(), false).copyInto(h)
|
||||
}
|
||||
}
|
||||
|
||||
val lastSize = when (message.size) {
|
||||
0 -> 0
|
||||
1 -> message[message.size - 1].size
|
||||
else -> (message.size - 1) * BLOCK_BYTES + message[message.size - 1].size
|
||||
|
||||
}
|
||||
|
||||
val lastBlockPadded = if (message.isNotEmpty()) {
|
||||
padToBlock(message[message.size - 1])
|
||||
} else {
|
||||
Array<UByte>(16) { 0U }
|
||||
}
|
||||
|
||||
compress(h, lastBlockPadded, lastSize.toBigInteger(), true).copyInto(h)
|
||||
|
||||
|
||||
return formatResult(h)
|
||||
}
|
||||
|
||||
private fun formatResult(h: Array<ULong>): Array<UByte> {
|
||||
return h.map {
|
||||
arrayOf(
|
||||
(it and 0xFFUL).toUByte(),
|
||||
(it shr 8 and 0xFFUL).toUByte(),
|
||||
(it shr 16 and 0xFFUL).toUByte(),
|
||||
(it shr 24 and 0xFFUL).toUByte(),
|
||||
(it shr 32 and 0xFFUL).toUByte(),
|
||||
(it shr 40 and 0xFFUL).toUByte(),
|
||||
(it shr 48 and 0xFFUL).toUByte(),
|
||||
(it shr 56 and 0xFFUL).toUByte()
|
||||
)
|
||||
}.flatMap {
|
||||
it.toList()
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
private fun padToBlock(unpadded: Array<UByte>): Array<UByte> {
|
||||
if (unpadded.size == BLOCK_BYTES) {
|
||||
return unpadded
|
||||
}
|
||||
|
||||
if (unpadded.size > BLOCK_BYTES) {
|
||||
throw IllegalStateException("Block larger than 128 bytes")
|
||||
}
|
||||
|
||||
return Array(BLOCK_BYTES) {
|
||||
when (it) {
|
||||
in 0 until unpadded.size -> unpadded[it]
|
||||
else -> 0U
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ExperimentalStdlibApi
|
||||
constructor(
|
||||
key: String?,
|
||||
requestedHashLenght: Int = 64
|
||||
) : this(
|
||||
(key?.encodeToByteArray()?.map { it.toUByte() }?.toTypedArray() ?: emptyArray<UByte>()),
|
||||
requestedHashLenght
|
||||
)
|
||||
|
||||
var h = iv.copyOf()
|
||||
var counter = BigInteger.ZERO
|
||||
var bufferCounter = 0
|
||||
var buffer = Array<UByte>(BLOCK_BYTES) { 0U }
|
||||
|
||||
|
||||
init {
|
||||
h[0] = h[0] xor 0x01010000UL xor (key?.run { size.toULong() shl 8 } ?: 0UL) xor hashLength.toULong()
|
||||
|
||||
if (!key.isNullOrEmpty()) {
|
||||
appendToBuffer(padToBlock(key), bufferCounter)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(array: Array<UByte>) {
|
||||
if (array.isEmpty()) {
|
||||
throw RuntimeException("Updating with empty array is not allowed. If you need empty hash, just call digest without updating")
|
||||
}
|
||||
|
||||
when {
|
||||
bufferCounter + array.size < BLOCK_BYTES -> appendToBuffer(array, bufferCounter)
|
||||
bufferCounter + array.size >= BLOCK_BYTES -> {
|
||||
val chunked = array.chunked(BLOCK_BYTES)
|
||||
chunked.forEach { chunk ->
|
||||
if (bufferCounter + chunk.size < BLOCK_BYTES) {
|
||||
appendToBuffer(chunk, bufferCounter)
|
||||
} else {
|
||||
chunk.copyInto(
|
||||
destination = buffer,
|
||||
destinationOffset = bufferCounter,
|
||||
startIndex = 0,
|
||||
endIndex = BLOCK_BYTES - bufferCounter
|
||||
)
|
||||
counter += BLOCK_BYTES
|
||||
consumeBlock(buffer)
|
||||
buffer = Array<UByte>(BLOCK_BYTES) {
|
||||
when (it) {
|
||||
in (0 until (chunk.size - (BLOCK_BYTES - bufferCounter))) -> {
|
||||
chunk[it + (BLOCK_BYTES - bufferCounter)]
|
||||
}
|
||||
else -> {
|
||||
0U
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
bufferCounter = chunk.size - (BLOCK_BYTES - bufferCounter)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ExperimentalStdlibApi
|
||||
fun update(input: String) {
|
||||
update(input.encodeToByteArray().map { it.toUByte() }.toTypedArray())
|
||||
}
|
||||
|
||||
private fun appendToBuffer(array: Array<UByte>, start: Int) {
|
||||
array.copyInto(destination = buffer, destinationOffset = start, startIndex = 0, endIndex = array.size)
|
||||
bufferCounter += array.size
|
||||
}
|
||||
|
||||
private fun consumeBlock(block: Array<UByte>) {
|
||||
h = compress(h, block, counter, false)
|
||||
}
|
||||
|
||||
fun digest(): Array<UByte> {
|
||||
val lastBlockPadded = padToBlock(buffer)
|
||||
counter += bufferCounter
|
||||
compress(h, lastBlockPadded, counter, true)
|
||||
|
||||
val result = formatResult(h)
|
||||
reset()
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
fun digestString(): String {
|
||||
return digest().map { it.toString(16) }.joinToString(separator = "")
|
||||
}
|
||||
|
||||
private fun reset() {
|
||||
h = iv.copyOf()
|
||||
counter = BigInteger.ZERO
|
||||
bufferCounter = 0
|
||||
buffer = Array<UByte>(BLOCK_BYTES) { 0U }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.sha
|
||||
|
||||
import com.ionspin.kotlin.crypto.Hash
|
||||
import com.ionspin.kotlin.crypto.chunked
|
||||
import com.ionspin.kotlin.crypto.rotateRight
|
||||
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 17-Jul-2019
|
||||
*/
|
||||
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class Sha256() : Hash {
|
||||
|
||||
companion object {
|
||||
const val BLOCK_SIZE = 512
|
||||
const val W_SIZE = 64
|
||||
const val UINT_MASK = 0xFFFFFFFFU
|
||||
const val BYTE_MASK_FROM_ULONG = 0xFFUL
|
||||
const val BYTE_MASK_FROM_UINT = 0xFFU
|
||||
|
||||
val iv = arrayOf(
|
||||
0x6a09e667U,
|
||||
0xbb67ae85U,
|
||||
0x3c6ef372U,
|
||||
0xa54ff53aU,
|
||||
0x510e527fU,
|
||||
0x9b05688cU,
|
||||
0x1f83d9abU,
|
||||
0x5be0cd19U
|
||||
)
|
||||
|
||||
val k = arrayOf(
|
||||
0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
|
||||
0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U,
|
||||
0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU, 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU,
|
||||
0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U,
|
||||
0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
|
||||
0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U,
|
||||
0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U,
|
||||
0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U, 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U
|
||||
)
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun digest(message : String) : Array<UByte> {
|
||||
return digest(message.encodeToByteArray().map { it.toUByte() }.toTypedArray())
|
||||
}
|
||||
|
||||
fun digest(message: Array<UByte>) : Array<UByte> {
|
||||
|
||||
var h0 = 0x6a09e667U
|
||||
var h1 = 0xbb67ae85U
|
||||
var h2 = 0x3c6ef372U
|
||||
var h3 = 0xa54ff53aU
|
||||
var h4 = 0x510e527fU
|
||||
var h5 = 0x9b05688cU
|
||||
var h6 = 0x1f83d9abU
|
||||
var h7 = 0x5be0cd19U
|
||||
|
||||
val originalMessageSizeInBits = message.size * 8
|
||||
|
||||
|
||||
//K such that L + 1 + K + 64 is a multiple of 512
|
||||
val expandedRemainderOf512 = (originalMessageSizeInBits + 65) % BLOCK_SIZE
|
||||
val zeroAddAmount = when (expandedRemainderOf512) {
|
||||
0 -> 0
|
||||
else -> (BLOCK_SIZE - expandedRemainderOf512) / 8
|
||||
}
|
||||
val expansionArray = Array<UByte>(zeroAddAmount + 1) {
|
||||
when (it) {
|
||||
0 -> 0b10000000U //TODO This wont work if there the byte needs to be shared with the L (length) ULong
|
||||
else -> 0U
|
||||
}
|
||||
}
|
||||
|
||||
val chunks = (message + expansionArray + originalMessageSizeInBits.toULong().toPaddedByteArray()).chunked(64)
|
||||
|
||||
chunks.forEach { chunk ->
|
||||
val w = Array<UInt>(W_SIZE) {
|
||||
when (it) {
|
||||
in 0 until 16 -> {
|
||||
var collected = (chunk[(it * 4)].toUInt() shl 24) +
|
||||
(chunk[(it * 4) + 1].toUInt() shl 16 ) +
|
||||
(chunk[(it * 4) + 2].toUInt() shl 8 ) +
|
||||
(chunk[(it * 4) + 3].toUInt())
|
||||
collected
|
||||
}
|
||||
else -> 0U
|
||||
}
|
||||
}
|
||||
for (i in 16 until W_SIZE) {
|
||||
val s0 = scheduleSigma0(w[i - 15])
|
||||
val s1 = scheduleSigma1(w[i - 2])
|
||||
w[i] = w[i-16] + s0 + w[i - 7] + s1
|
||||
}
|
||||
|
||||
var a = h0
|
||||
var b = h1
|
||||
var c = h2
|
||||
var d = h3
|
||||
var e = h4
|
||||
var f = h5
|
||||
var g = h6
|
||||
var h = h7
|
||||
|
||||
for (i in 0 until W_SIZE) {
|
||||
val s1 = compressionSigma1(e)
|
||||
val ch = ch(e, f, g)
|
||||
val temp1 = h + s1 + ch + k[i] + w[i]
|
||||
val s0 = compressionSigma0(a)
|
||||
val maj = maj(a,b,c)
|
||||
val temp2 = s0 + maj
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = d + temp1
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = temp1 + temp2
|
||||
}
|
||||
|
||||
h0 += a
|
||||
h1 += b
|
||||
h2 += c
|
||||
h3 += d
|
||||
h4 += e
|
||||
h5 += f
|
||||
h6 += g
|
||||
h7 += h
|
||||
|
||||
}
|
||||
|
||||
val digest = h0.toPaddedByteArray() +
|
||||
h1.toPaddedByteArray() +
|
||||
h2.toPaddedByteArray() +
|
||||
h3.toPaddedByteArray() +
|
||||
h4.toPaddedByteArray() +
|
||||
h5.toPaddedByteArray() +
|
||||
h6.toPaddedByteArray() +
|
||||
h7.toPaddedByteArray()
|
||||
return digest
|
||||
}
|
||||
|
||||
private fun scheduleSigma0(value: UInt): UInt {
|
||||
return value.rotateRight(7) xor value.rotateRight(18) xor (value shr 3)
|
||||
}
|
||||
|
||||
private fun scheduleSigma1(value : UInt) : UInt {
|
||||
return value.rotateRight(17) xor value.rotateRight(19) xor (value shr 10)
|
||||
}
|
||||
|
||||
private fun compressionSigma0(a : UInt) : UInt {
|
||||
return (a rotateRight 2) xor (a rotateRight 13) xor (a rotateRight 22)
|
||||
}
|
||||
|
||||
private fun compressionSigma1(e : UInt) : UInt {
|
||||
return (e rotateRight 6) xor (e rotateRight 11) xor (e rotateRight 25)
|
||||
}
|
||||
|
||||
private fun ch(x : UInt, y : UInt, z : UInt) : UInt {
|
||||
return ((x and y) xor ((x xor UINT_MASK) and z))
|
||||
}
|
||||
|
||||
private fun maj(x : UInt, y : UInt, z : UInt) : UInt {
|
||||
return (((x and y) xor (x and z) xor (y and z)))
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun ULong.toPaddedByteArray(): Array<UByte> {
|
||||
val byteMask = BYTE_MASK_FROM_ULONG
|
||||
return Array(8) {
|
||||
when (it) {
|
||||
7 -> (this and byteMask).toUByte()
|
||||
6 -> ((this shr 8) and byteMask).toUByte()
|
||||
5 -> ((this shr 16) and byteMask).toUByte()
|
||||
4 -> ((this shr 24) and byteMask).toUByte()
|
||||
3 -> ((this shr 32) and byteMask).toUByte()
|
||||
2 -> ((this shr 40) and byteMask).toUByte()
|
||||
1 -> ((this shr 48) and byteMask).toUByte()
|
||||
0 -> ((this shr 54) and byteMask).toUByte()
|
||||
else -> throw RuntimeException("Invalid conversion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun UInt.toPaddedByteArray(): Array<UByte> {
|
||||
val byteMask = BYTE_MASK_FROM_UINT
|
||||
return Array(4) {
|
||||
when (it) {
|
||||
3 -> (this and byteMask).toUByte()
|
||||
2 -> ((this shr 8) and byteMask).toUByte()
|
||||
1 -> ((this shr 16) and byteMask).toUByte()
|
||||
0 -> ((this shr 24) and byteMask).toUByte()
|
||||
else -> throw RuntimeException("Invalid conversion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.sha
|
||||
|
||||
import com.ionspin.kotlin.crypto.Hash
|
||||
import com.ionspin.kotlin.crypto.chunked
|
||||
import com.ionspin.kotlin.crypto.rotateRight
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 18-Jul-2019
|
||||
*/
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class Sha512 : Hash {
|
||||
companion object {
|
||||
const val BLOCK_SIZE = 1024
|
||||
const val ULONG_MASK = 0xFFFFFFFFFFFFFFFFUL
|
||||
|
||||
val k = arrayOf(
|
||||
0x428a2f98d728ae22UL,
|
||||
0x7137449123ef65cdUL,
|
||||
0xb5c0fbcfec4d3b2fUL,
|
||||
0xe9b5dba58189dbbcUL,
|
||||
0x3956c25bf348b538UL,
|
||||
0x59f111f1b605d019UL,
|
||||
0x923f82a4af194f9bUL,
|
||||
0xab1c5ed5da6d8118UL,
|
||||
0xd807aa98a3030242UL,
|
||||
0x12835b0145706fbeUL,
|
||||
0x243185be4ee4b28cUL,
|
||||
0x550c7dc3d5ffb4e2UL,
|
||||
0x72be5d74f27b896fUL,
|
||||
0x80deb1fe3b1696b1UL,
|
||||
0x9bdc06a725c71235UL,
|
||||
0xc19bf174cf692694UL,
|
||||
0xe49b69c19ef14ad2UL,
|
||||
0xefbe4786384f25e3UL,
|
||||
0x0fc19dc68b8cd5b5UL,
|
||||
0x240ca1cc77ac9c65UL,
|
||||
0x2de92c6f592b0275UL,
|
||||
0x4a7484aa6ea6e483UL,
|
||||
0x5cb0a9dcbd41fbd4UL,
|
||||
0x76f988da831153b5UL,
|
||||
0x983e5152ee66dfabUL,
|
||||
0xa831c66d2db43210UL,
|
||||
0xb00327c898fb213fUL,
|
||||
0xbf597fc7beef0ee4UL,
|
||||
0xc6e00bf33da88fc2UL,
|
||||
0xd5a79147930aa725UL,
|
||||
0x06ca6351e003826fUL,
|
||||
0x142929670a0e6e70UL,
|
||||
0x27b70a8546d22ffcUL,
|
||||
0x2e1b21385c26c926UL,
|
||||
0x4d2c6dfc5ac42aedUL,
|
||||
0x53380d139d95b3dfUL,
|
||||
0x650a73548baf63deUL,
|
||||
0x766a0abb3c77b2a8UL,
|
||||
0x81c2c92e47edaee6UL,
|
||||
0x92722c851482353bUL,
|
||||
0xa2bfe8a14cf10364UL,
|
||||
0xa81a664bbc423001UL,
|
||||
0xc24b8b70d0f89791UL,
|
||||
0xc76c51a30654be30UL,
|
||||
0xd192e819d6ef5218UL,
|
||||
0xd69906245565a910UL,
|
||||
0xf40e35855771202aUL,
|
||||
0x106aa07032bbd1b8UL,
|
||||
0x19a4c116b8d2d0c8UL,
|
||||
0x1e376c085141ab53UL,
|
||||
0x2748774cdf8eeb99UL,
|
||||
0x34b0bcb5e19b48a8UL,
|
||||
0x391c0cb3c5c95a63UL,
|
||||
0x4ed8aa4ae3418acbUL,
|
||||
0x5b9cca4f7763e373UL,
|
||||
0x682e6ff3d6b2b8a3UL,
|
||||
0x748f82ee5defb2fcUL,
|
||||
0x78a5636f43172f60UL,
|
||||
0x84c87814a1f0ab72UL,
|
||||
0x8cc702081a6439ecUL,
|
||||
0x90befffa23631e28UL,
|
||||
0xa4506cebde82bde9UL,
|
||||
0xbef9a3f7b2c67915UL,
|
||||
0xc67178f2e372532bUL,
|
||||
0xca273eceea26619cUL,
|
||||
0xd186b8c721c0c207UL,
|
||||
0xeada7dd6cde0eb1eUL,
|
||||
0xf57d4f7fee6ed178UL,
|
||||
0x06f067aa72176fbaUL,
|
||||
0x0a637dc5a2c898a6UL,
|
||||
0x113f9804bef90daeUL,
|
||||
0x1b710b35131c471bUL,
|
||||
0x28db77f523047d84UL,
|
||||
0x32caab7b40c72493UL,
|
||||
0x3c9ebe0a15c9bebcUL,
|
||||
0x431d67c49c100d4cUL,
|
||||
0x4cc5d4becb3e42b6UL,
|
||||
0x597f299cfc657e2aUL,
|
||||
0x5fcb6fab3ad6faecUL,
|
||||
0x6c44198c4a475817UL
|
||||
)
|
||||
|
||||
val iv = arrayOf(
|
||||
0x6a09e667f3bcc908UL,
|
||||
0xbb67ae8584caa73bUL,
|
||||
0x3c6ef372fe94f82bUL,
|
||||
0xa54ff53a5f1d36f1UL,
|
||||
0x510e527fade682d1UL,
|
||||
0x9b05688c2b3e6c1fUL,
|
||||
0x1f83d9abfb41bd6bUL,
|
||||
0x5be0cd19137e2179UL
|
||||
)
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
fun digest(message: String): Array<UByte> {
|
||||
return digest(message.encodeToByteArray().map { it.toUByte() }.toTypedArray())
|
||||
}
|
||||
|
||||
fun digest(message: Array<UByte>): Array<UByte> {
|
||||
|
||||
var h0 = 0x6a09e667f3bcc908UL
|
||||
var h1 = 0xbb67ae8584caa73bUL
|
||||
var h2 = 0x3c6ef372fe94f82bUL
|
||||
var h3 = 0xa54ff53a5f1d36f1UL
|
||||
var h4 = 0x510e527fade682d1UL
|
||||
var h5 = 0x9b05688c2b3e6c1fUL
|
||||
var h6 = 0x1f83d9abfb41bd6bUL
|
||||
var h7 = 0x5be0cd19137e2179UL
|
||||
|
||||
val originalMessageSizeInBits = message.size * 8
|
||||
|
||||
|
||||
//K such that L + 1 + K + 64 is a multiple of 512
|
||||
val expandedRemainderOf1024 = (originalMessageSizeInBits + 129) % BLOCK_SIZE
|
||||
val zeroAddAmount = when (expandedRemainderOf1024) {
|
||||
0 -> 0
|
||||
else -> (BLOCK_SIZE - expandedRemainderOf1024) / 8
|
||||
}
|
||||
val expansionArray = Array<UByte>(zeroAddAmount + 1) {
|
||||
when (it) {
|
||||
0 -> 0b10000000U //TODO This wont work if there the byte needs to be shared with the L (length) ULong
|
||||
else -> 0U
|
||||
}
|
||||
}
|
||||
|
||||
val chunks =
|
||||
(message + expansionArray + originalMessageSizeInBits.toULong().toPadded128BitByteArray()).chunked(128)
|
||||
|
||||
chunks.forEach { chunk ->
|
||||
val w = Array<ULong>(80) {
|
||||
when (it) {
|
||||
in 0 until 16 -> {
|
||||
var collected = (chunk[(it * 8)].toULong() shl 56) +
|
||||
(chunk[(it * 8) + 1].toULong() shl 48) +
|
||||
(chunk[(it * 8) + 2].toULong() shl 40) +
|
||||
(chunk[(it * 8) + 3].toULong() shl 32) +
|
||||
(chunk[(it * 8) + 4].toULong() shl 24) +
|
||||
(chunk[(it * 8) + 5].toULong() shl 16) +
|
||||
(chunk[(it * 8) + 6].toULong() shl 8) +
|
||||
(chunk[(it * 8) + 7].toULong())
|
||||
collected
|
||||
}
|
||||
else -> 0UL
|
||||
}
|
||||
}
|
||||
for (i in 16 until 80) {
|
||||
val s0 = scheduleSigma0(w[i - 15])
|
||||
val s1 = scheduleSigma1(w[i - 2])
|
||||
w[i] = w[i - 16] + s0 + w[i - 7] + s1
|
||||
}
|
||||
|
||||
var a = h0
|
||||
var b = h1
|
||||
var c = h2
|
||||
var d = h3
|
||||
var e = h4
|
||||
var f = h5
|
||||
var g = h6
|
||||
var h = h7
|
||||
|
||||
for (i in 0 until 80) {
|
||||
val s1 = compressionSigma1(e)
|
||||
val ch = ch(e, f, g)
|
||||
val temp1 = h + s1 + ch + k[i] + w[i]
|
||||
val s0 = compressionSigma0(a)
|
||||
val maj = maj(a, b, c)
|
||||
val temp2 = s0 + maj
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = d + temp1
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = temp1 + temp2
|
||||
}
|
||||
|
||||
h0 += a
|
||||
h1 += b
|
||||
h2 += c
|
||||
h3 += d
|
||||
h4 += e
|
||||
h5 += f
|
||||
h6 += g
|
||||
h7 += h
|
||||
|
||||
}
|
||||
|
||||
val digest = h0.toPaddedByteArray() +
|
||||
h1.toPaddedByteArray() +
|
||||
h2.toPaddedByteArray() +
|
||||
h3.toPaddedByteArray() +
|
||||
h4.toPaddedByteArray() +
|
||||
h5.toPaddedByteArray() +
|
||||
h6.toPaddedByteArray() +
|
||||
h7.toPaddedByteArray()
|
||||
return digest
|
||||
}
|
||||
|
||||
private fun scheduleSigma0(value: ULong): ULong {
|
||||
return value.rotateRight(1) xor value.rotateRight(8) xor (value shr 7)
|
||||
}
|
||||
|
||||
private fun scheduleSigma1(value: ULong): ULong {
|
||||
return value.rotateRight(19) xor value.rotateRight(61) xor (value shr 6)
|
||||
}
|
||||
|
||||
private fun compressionSigma0(e: ULong): ULong {
|
||||
return (e rotateRight 28) xor (e rotateRight 34) xor (e rotateRight 39)
|
||||
}
|
||||
|
||||
private fun compressionSigma1(a: ULong): ULong {
|
||||
return (a rotateRight 14) xor (a rotateRight 18) xor (a rotateRight 41)
|
||||
}
|
||||
|
||||
private fun ch(x: ULong, y: ULong, z: ULong): ULong {
|
||||
return ((x and y) xor ((x xor ULONG_MASK) and z))
|
||||
}
|
||||
|
||||
private fun maj(x: ULong, y: ULong, z: ULong): ULong {
|
||||
return ((x and y) xor (x and z) xor (y and z))
|
||||
}
|
||||
|
||||
|
||||
private fun ULong.toPaddedByteArray(): Array<UByte> {
|
||||
val byteMask = 0xFFUL
|
||||
//Ignore messages longer than 64 bits for now
|
||||
return Array(8) {
|
||||
when (it) {
|
||||
7 -> (this and byteMask).toUByte()
|
||||
6 -> ((this shr 8) and byteMask).toUByte()
|
||||
5 -> ((this shr 16) and byteMask).toUByte()
|
||||
4 -> ((this shr 24) and byteMask).toUByte()
|
||||
3 -> ((this shr 32) and byteMask).toUByte()
|
||||
2 -> ((this shr 40) and byteMask).toUByte()
|
||||
1 -> ((this shr 48) and byteMask).toUByte()
|
||||
0 -> ((this shr 56) and byteMask).toUByte()
|
||||
else -> 0U
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ULong.toPadded128BitByteArray(): Array<UByte> {
|
||||
val byteMask = 0xFFUL
|
||||
//Ignore messages longer than 64 bits for now
|
||||
return Array(16) {
|
||||
when (it) {
|
||||
15 -> (this and byteMask).toUByte()
|
||||
14 -> ((this shr 8) and byteMask).toUByte()
|
||||
13 -> ((this shr 16) and byteMask).toUByte()
|
||||
12 -> ((this shr 24) and byteMask).toUByte()
|
||||
11 -> ((this shr 32) and byteMask).toUByte()
|
||||
10 -> ((this shr 40) and byteMask).toUByte()
|
||||
9 -> ((this shr 48) and byteMask).toUByte()
|
||||
8 -> ((this shr 54) and byteMask).toUByte()
|
||||
else -> 0U
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
import com.ionspin.kotlin.crypto.blake2b.Blake2b
|
||||
import com.ionspin.kotlin.crypto.sha.Sha256
|
||||
import com.ionspin.kotlin.crypto.sha.Sha512
|
||||
import kotlin.test.Test
|
||||
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
@ExperimentalStdlibApi
|
||||
class ReadmeTest {
|
||||
|
||||
@Test
|
||||
fun blake2bObjectExample() {
|
||||
val input = "abc"
|
||||
val result = Blake2b.digest(input)
|
||||
//@formatter:off
|
||||
val expectedResult = arrayOf<UByte>(
|
||||
0xBAU,0x80U,0xA5U,0x3FU,0x98U,0x1CU,0x4DU,0x0DU,0x6AU,0x27U,0x97U,0xB6U,0x9FU,0x12U,0xF6U,0xE9U,
|
||||
0x4CU,0x21U,0x2FU,0x14U,0x68U,0x5AU,0xC4U,0xB7U,0x4BU,0x12U,0xBBU,0x6FU,0xDBU,0xFFU,0xA2U,0xD1U,
|
||||
0x7DU,0x87U,0xC5U,0x39U,0x2AU,0xABU,0x79U,0x2DU,0xC2U,0x52U,0xD5U,0xDEU,0x45U,0x33U,0xCCU,0x95U,
|
||||
0x18U,0xD3U,0x8AU,0xA8U,0xDBU,0xF1U,0x92U,0x5AU,0xB9U,0x23U,0x86U,0xEDU,0xD4U,0x00U,0x99U,0x23U
|
||||
)
|
||||
//@formatter:on
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun blake2bInstanceExample() {
|
||||
val test = "abc"
|
||||
val key = "key"
|
||||
val blake2b = Blake2b(key)
|
||||
blake2b.update(test)
|
||||
val result = blake2b.digest()
|
||||
|
||||
assertTrue {
|
||||
result.isNotEmpty()
|
||||
}
|
||||
val expectedResult = ("5c6a9a4ae911c02fb7e71a991eb9aea371ae993d4842d206e" +
|
||||
"6020d46f5e41358c6d5c277c110ef86c959ed63e6ecaaaceaaff38019a43264ae06acf73b9550b1")
|
||||
.chunked(2).map { it.toUByte(16) }.toTypedArray()
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun sha256Example() {
|
||||
val input ="abc"
|
||||
val result = Sha256.digest(message = input)
|
||||
val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun sha512Example() {
|
||||
val input ="abc"
|
||||
val result = Sha512.digest(message = input.encodeToByteArray().map { it.toUByte() }.toTypedArray())
|
||||
println(result.map {it.toString(16)})
|
||||
val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
import com.ionspin.kotlin.crypto.chunked
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 17-Jul-2019
|
||||
*/
|
||||
class UtilTest {
|
||||
|
||||
@Test
|
||||
fun testSlicer() {
|
||||
val array = arrayOf(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)
|
||||
val chunked = array.chunked(2)
|
||||
assertTrue {
|
||||
chunked.size == 9 && chunked[8][0] == 17
|
||||
}
|
||||
}
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.blake2b
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 14-Jul-2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
@ExperimentalStdlibApi
|
||||
class Blake2BTest {
|
||||
|
||||
@Test
|
||||
fun testMultipleBlocks() {
|
||||
val test = "1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890"
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
//Generated with b2sum 8.31
|
||||
val expectedResult = arrayOf<UByte>(
|
||||
//@formatter:off
|
||||
0x2fU, 0x49U, 0xaeU, 0xb6U, 0x13U, 0xe3U, 0x4eU, 0x92U, 0x4eU, 0x17U, 0x5aU, 0x6aU, 0xf2U, 0xfaU, 0xadU,
|
||||
0x7bU, 0xc7U, 0x82U, 0x35U, 0xf9U, 0xc5U, 0xe4U, 0x61U, 0xc6U, 0x8fU, 0xd5U, 0xb4U, 0x07U, 0xeeU, 0x8eU,
|
||||
0x2fU, 0x0dU, 0x2fU, 0xb4U, 0xc0U, 0x7dU, 0x7eU, 0x4aU, 0x72U, 0x40U, 0x46U, 0x12U, 0xd9U, 0x28U, 0x99U,
|
||||
0xafU, 0x8aU, 0x32U, 0x8fU, 0x3bU, 0x61U, 0x4eU, 0xd7U, 0x72U, 0x44U, 0xb4U, 0x81U, 0x15U, 0x1dU, 0x40U,
|
||||
0xb1U, 0x1eU, 0x32U, 0xa4U
|
||||
//@formatter:on
|
||||
)
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun singleBlockTest() {
|
||||
val test = "1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890" +
|
||||
"1234567890"
|
||||
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
val expectedResultString = "800bb78cd4da18995c8074713bb674" +
|
||||
"3cd94b2b6490a693fe4000ed00833b88b7b474d94af9cfed246b1b" +
|
||||
"4ce1935a76154d7ea7c410493557741d18ec3a08da75"
|
||||
val expectedResult = expectedResultString.chunked(2).map { it.toUByte(16) }.toTypedArray()
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testDigest() {
|
||||
val test = "111111111122222222223333333333333"
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
//Generated with b2sum 8.31
|
||||
val expectedResult = arrayOf<UByte>(
|
||||
//@formatter:off
|
||||
0xe0U, 0xabU, 0xb7U, 0x5dU, 0xb2U, 0xc8U, 0xe1U, 0x3cU, 0x5fU, 0x1dU, 0x9fU, 0x55U, 0xc8U, 0x4eU, 0xacU, 0xd7U,
|
||||
0xa8U, 0x44U, 0x57U, 0x9bU, 0xc6U, 0x9cU, 0x47U, 0x26U, 0xebU, 0xeaU, 0x2bU, 0xafU, 0x9eU, 0x44U, 0x16U, 0xebU,
|
||||
0xb8U, 0x0aU, 0xc5U, 0xfbU, 0xb0U, 0xe8U, 0xe5U, 0x6eU, 0xc5U, 0x49U, 0x0dU, 0x75U, 0x59U, 0x32U, 0x13U, 0xb4U,
|
||||
0x76U, 0x50U, 0x5eU, 0x6aU, 0xd8U, 0x74U, 0x67U, 0x14U, 0x64U, 0xb0U, 0xf8U, 0xb5U, 0x50U, 0x60U, 0x62U, 0xfbU
|
||||
//@formatter:on
|
||||
)
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFigestWithKey() {
|
||||
val test = "abc"
|
||||
val key = "key"
|
||||
|
||||
val result = Blake2b.digest(test, key)
|
||||
|
||||
assertTrue {
|
||||
result.isNotEmpty()
|
||||
}
|
||||
val expectedResult = ("5c6a9a4ae911c02fb7e71a991eb9aea371ae993d4842d206e" +
|
||||
"6020d46f5e41358c6d5c277c110ef86c959ed63e6ecaaaceaaff38019a43264ae06acf73b9550b1")
|
||||
.chunked(2).map { it.toUByte(16) }.toTypedArray()
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testDigestFromRfc() {
|
||||
val test = "abc"
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
//@formatter:off
|
||||
val expectedResult = arrayOf<UByte>(
|
||||
|
||||
0xBAU,0x80U,0xA5U,0x3FU,0x98U,0x1CU,0x4DU,0x0DU,0x6AU,0x27U,0x97U,0xB6U,0x9FU,0x12U,0xF6U,0xE9U,
|
||||
0x4CU,0x21U,0x2FU,0x14U,0x68U,0x5AU,0xC4U,0xB7U,0x4BU,0x12U,0xBBU,0x6FU,0xDBU,0xFFU,0xA2U,0xD1U,
|
||||
0x7DU,0x87U,0xC5U,0x39U,0x2AU,0xABU,0x79U,0x2DU,0xC2U,0x52U,0xD5U,0xDEU,0x45U,0x33U,0xCCU,0x95U,
|
||||
0x18U,0xD3U,0x8AU,0xA8U,0xDBU,0xF1U,0x92U,0x5AU,0xB9U,0x23U,0x86U,0xEDU,0xD4U,0x00U,0x99U,0x23U
|
||||
|
||||
)
|
||||
//@formatter:on
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val message = arrayOf(
|
||||
0x0000000000636261UL, 0x0000000000000000UL, 0x0000000000000000UL,
|
||||
0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL,
|
||||
0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL,
|
||||
0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL,
|
||||
0x0000000000000000UL, 0x0000000000000000UL, 0x0000000000000000UL,
|
||||
0x0000000000000000UL
|
||||
)
|
||||
|
||||
val mixChain = arrayOf(
|
||||
arrayOf(
|
||||
0x6A09E667F2BDC948UL, 0xBB67AE8584CAA73BUL, 0x3C6EF372FE94F82BUL,
|
||||
0xA54FF53A5F1D36F1UL, 0x510E527FADE682D1UL, 0x9B05688C2B3E6C1FUL,
|
||||
0x1F83D9ABFB41BD6BUL, 0x5BE0CD19137E2179UL, 0x6A09E667F3BCC908UL,
|
||||
0xBB67AE8584CAA73BUL, 0x3C6EF372FE94F82BUL, 0xA54FF53A5F1D36F1UL,
|
||||
0x510E527FADE682D2UL, 0x9B05688C2B3E6C1FUL, 0xE07C265404BE4294UL,
|
||||
0x5BE0CD19137E2179UL
|
||||
),
|
||||
arrayOf(
|
||||
0x86B7C1568029BB79UL, 0xC12CBCC809FF59F3UL, 0xC6A5214CC0EACA8EUL,
|
||||
0x0C87CD524C14CC5DUL, 0x44EE6039BD86A9F7UL, 0xA447C850AA694A7EUL,
|
||||
0xDE080F1BB1C0F84BUL, 0x595CB8A9A1ACA66CUL, 0xBEC3AE837EAC4887UL,
|
||||
0x6267FC79DF9D6AD1UL, 0xFA87B01273FA6DBEUL, 0x521A715C63E08D8AUL,
|
||||
0xE02D0975B8D37A83UL, 0x1C7B754F08B7D193UL, 0x8F885A76B6E578FEUL,
|
||||
0x2318A24E2140FC64UL
|
||||
),
|
||||
arrayOf(
|
||||
0x53281E83806010F2UL, 0x3594B403F81B4393UL, 0x8CD63C7462DE0DFFUL,
|
||||
0x85F693F3DA53F974UL, 0xBAABDBB2F386D9AEUL, 0xCA5425AEC65A10A8UL,
|
||||
0xC6A22E2FF0F7AA48UL, 0xC6A56A51CB89C595UL, 0x224E6A3369224F96UL,
|
||||
0x500E125E58A92923UL, 0xE9E4AD0D0E1A0D48UL, 0x85DF9DC143C59A74UL,
|
||||
0x92A3AAAA6D952B7FUL, 0xC5FDF71090FAE853UL, 0x2A8A40F15A462DD0UL,
|
||||
0x572D17EFFDD37358UL
|
||||
),
|
||||
arrayOf(
|
||||
0x60ED96AA7AD41725UL, 0xE46A743C71800B9DUL, 0x1A04B543A01F156BUL,
|
||||
0xA2F8716E775C4877UL, 0xDA0A61BCDE4267EAUL, 0xB1DD230754D7BDEEUL,
|
||||
0x25A1422779E06D14UL, 0xE6823AE4C3FF58A5UL, 0xA1677E19F37FD5DAUL,
|
||||
0x22BDCE6976B08C51UL, 0xF1DE8696BEC11BF1UL, 0xA0EBD586A4A1D2C8UL,
|
||||
0xC804EBAB11C99FA9UL, 0x8E0CEC959C715793UL, 0x7C45557FAE0D4D89UL,
|
||||
0x716343F52FDD265EUL
|
||||
),
|
||||
arrayOf(
|
||||
0xBB2A77D3A8382351UL, 0x45EB47971F23B103UL, 0x98BE297F6E45C684UL,
|
||||
0xA36077DEE3370B89UL, 0x8A03C4CB7E97590AUL, 0x24192E49EBF54EA0UL,
|
||||
0x4F82C9401CB32D7AUL, 0x8CCD013726420DC4UL, 0xA9C9A8F17B1FC614UL,
|
||||
0x55908187977514A0UL, 0x5B44273E66B19D27UL, 0xB6D5C9FCA2579327UL,
|
||||
0x086092CFB858437EUL, 0x5C4BE2156DBEECF9UL, 0x2EFEDE99ED4EFF16UL,
|
||||
0x3E7B5F234CD1F804UL
|
||||
),
|
||||
arrayOf(
|
||||
0xC79C15B3D423B099UL, 0x2DA2224E8DA97556UL, 0x77D2B26DF1C45C55UL,
|
||||
0x8934EB09A3456052UL, 0x0F6D9EEED157DA2AUL, 0x6FE66467AF88C0A9UL,
|
||||
0x4EB0B76284C7AAFBUL, 0x299C8E725D954697UL, 0xB2240B59E6D567D3UL,
|
||||
0x2643C2370E49EBFDUL, 0x79E02EEF20CDB1AEUL, 0x64B3EED7BB602F39UL,
|
||||
0xB97D2D439E4DF63DUL, 0xC718E755294C9111UL, 0x1F0893F2772BB373UL,
|
||||
0x1205EA4A7859807DUL
|
||||
),
|
||||
arrayOf(
|
||||
0xE58F97D6385BAEE4UL, 0x7640AA9764DA137AUL, 0xDEB4C7C23EFE287EUL,
|
||||
0x70F6F41C8783C9F6UL, 0x7127CD48C76A7708UL, 0x9E472AF0BE3DB3F6UL,
|
||||
0x0F244C62DDF71788UL, 0x219828AA83880842UL, 0x41CCA9073C8C4D0DUL,
|
||||
0x5C7912BC10DF3B4BUL, 0xA2C3ABBD37510EE2UL, 0xCB5668CC2A9F7859UL,
|
||||
0x8733794F07AC1500UL, 0xC67A6BE42335AA6FUL, 0xACB22B28681E4C82UL,
|
||||
0xDB2161604CBC9828UL
|
||||
),
|
||||
arrayOf(
|
||||
0x6E2D286EEADEDC81UL, 0xBCF02C0787E86358UL, 0x57D56A56DD015EDFUL,
|
||||
0x55D899D40A5D0D0AUL, 0x819415B56220C459UL, 0xB63C479A6A769F02UL,
|
||||
0x258E55E0EC1F362AUL, 0x3A3B4EC60E19DFDCUL, 0x04D769B3FCB048DBUL,
|
||||
0xB78A9A33E9BFF4DDUL, 0x5777272AE1E930C0UL, 0x5A387849E578DBF6UL,
|
||||
0x92AAC307CF2C0AFCUL, 0x30AACCC4F06DAFAAUL, 0x483893CC094F8863UL,
|
||||
0xE03C6CC89C26BF92UL
|
||||
),
|
||||
arrayOf(
|
||||
0xFFC83ECE76024D01UL, 0x1BE7BFFB8C5CC5F9UL, 0xA35A18CBAC4C65B7UL,
|
||||
0xB7C2C7E6D88C285FUL, 0x81937DA314A50838UL, 0xE1179523A2541963UL,
|
||||
0x3A1FAD7106232B8FUL, 0x1C7EDE92AB8B9C46UL, 0xA3C2D35E4F685C10UL,
|
||||
0xA53D3F73AA619624UL, 0x30BBCC0285A22F65UL, 0xBCEFBB6A81539E5DUL,
|
||||
0x3841DEF6F4C9848AUL, 0x98662C85FBA726D4UL, 0x7762439BD5A851BDUL,
|
||||
0xB0B9F0D443D1A889UL
|
||||
),
|
||||
arrayOf(
|
||||
0x753A70A1E8FAEADDUL, 0x6B0D43CA2C25D629UL, 0xF8343BA8B94F8C0BUL,
|
||||
0xBC7D062B0DB5CF35UL, 0x58540EE1B1AEBC47UL, 0x63C5B9B80D294CB9UL,
|
||||
0x490870ECAD27DEBDUL, 0xB2A90DDF667287FEUL, 0x316CC9EBEEFAD8FCUL,
|
||||
0x4A466BCD021526A4UL, 0x5DA7F7638CEC5669UL, 0xD9C8826727D306FCUL,
|
||||
0x88ED6C4F3BD7A537UL, 0x19AE688DDF67F026UL, 0x4D8707AAB40F7E6DUL,
|
||||
0xFD3F572687FEA4F1UL
|
||||
),
|
||||
arrayOf(
|
||||
0xE630C747CCD59C4FUL, 0xBC713D41127571CAUL, 0x46DB183025025078UL,
|
||||
0x6727E81260610140UL, 0x2D04185EAC2A8CBAUL, 0x5F311B88904056ECUL,
|
||||
0x40BD313009201AABUL, 0x0099D4F82A2A1EABUL, 0x6DD4FBC1DE60165DUL,
|
||||
0xB3B0B51DE3C86270UL, 0x900AEE2F233B08E5UL, 0xA07199D87AD058D8UL,
|
||||
0x2C6B25593D717852UL, 0x37E8CA471BEAA5F8UL, 0x2CFC1BAC10EF4457UL,
|
||||
0x01369EC18746E775UL
|
||||
),
|
||||
arrayOf(
|
||||
0xE801F73B9768C760UL, 0x35C6D22320BE511DUL, 0x306F27584F65495EUL,
|
||||
0xB51776ADF569A77BUL, 0xF4F1BE86690B3C34UL, 0x3CC88735D1475E4BUL,
|
||||
0x5DAC67921FF76949UL, 0x1CDB9D31AD70CC4EUL, 0x35BA354A9C7DF448UL,
|
||||
0x4929CBE45679D73EUL, 0x733D1A17248F39DBUL, 0x92D57B736F5F170AUL,
|
||||
0x61B5C0A41D491399UL, 0xB5C333457E12844AUL, 0xBD696BE010D0D889UL,
|
||||
0x02231E1A917FE0BDUL
|
||||
),
|
||||
arrayOf(
|
||||
0x12EF8A641EC4F6D6UL, 0xBCED5DE977C9FAF5UL, 0x733CA476C5148639UL,
|
||||
0x97DF596B0610F6FCUL, 0xF42C16519AD5AFA7UL, 0xAA5AC1888E10467EUL,
|
||||
0x217D930AA51787F3UL, 0x906A6FF19E573942UL, 0x75AB709BD3DCBF24UL,
|
||||
0xEE7CE1F345947AA4UL, 0xF8960D6C2FAF5F5EUL, 0xE332538A36B6D246UL,
|
||||
0x885BEF040EF6AA0BUL, 0xA4939A417BFB78A3UL, 0x646CBB7AF6DCE980UL,
|
||||
0xE813A23C60AF3B82UL
|
||||
)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testMixRound() {
|
||||
for (i in 0 until mixChain.size - 1) {
|
||||
val inputRound = mixChain[i]
|
||||
val round = i
|
||||
val result = Blake2b.mixRound(inputRound, message, round)
|
||||
val expectedResult = mixChain[i + 1]
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.blake2b
|
||||
|
||||
import com.ionspin.kotlin.crypto.util.testBlocking
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
@ExperimentalStdlibApi
|
||||
class Blake2bInstanceTest {
|
||||
|
||||
@Test
|
||||
fun testUpdateableBlake2b() {
|
||||
val updates = 14
|
||||
val input = "1234567890"
|
||||
val expectedResult = arrayOf<UByte>(
|
||||
//@formatter:off
|
||||
0x2fU, 0x49U, 0xaeU, 0xb6U, 0x13U, 0xe3U, 0x4eU, 0x92U, 0x4eU, 0x17U, 0x5aU, 0x6aU, 0xf2U, 0xfaU, 0xadU,
|
||||
0x7bU, 0xc7U, 0x82U, 0x35U, 0xf9U, 0xc5U, 0xe4U, 0x61U, 0xc6U, 0x8fU, 0xd5U, 0xb4U, 0x07U, 0xeeU, 0x8eU,
|
||||
0x2fU, 0x0dU, 0x2fU, 0xb4U, 0xc0U, 0x7dU, 0x7eU, 0x4aU, 0x72U, 0x40U, 0x46U, 0x12U, 0xd9U, 0x28U, 0x99U,
|
||||
0xafU, 0x8aU, 0x32U, 0x8fU, 0x3bU, 0x61U, 0x4eU, 0xd7U, 0x72U, 0x44U, 0xb4U, 0x81U, 0x15U, 0x1dU, 0x40U,
|
||||
0xb1U, 0x1eU, 0x32U, 0xa4U
|
||||
//@formatter:on
|
||||
)
|
||||
|
||||
val blake2b = Blake2b()
|
||||
for (i in 0 until updates) {
|
||||
blake2b.update(input)
|
||||
}
|
||||
val result = blake2b.digest()
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDigestToString() {
|
||||
val updates = 14
|
||||
val input = "1234567890"
|
||||
val expectedResult = "2F49AEB613E34E924E175A6AF2FAAD7BC78235F9C5E461C68FD5B47E".toLowerCase() +
|
||||
"E8E2FD2FB4C07D7E4A72404612D92899AF8A328F3B614ED77244B481151D40B11E32A4".toLowerCase()
|
||||
|
||||
val blake2b = Blake2b()
|
||||
for (i in 0 until updates) {
|
||||
blake2b.update(input)
|
||||
}
|
||||
val result = blake2b.digestString()
|
||||
assertTrue {
|
||||
result == expectedResult
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDigestWithKey() {
|
||||
val test = "abc"
|
||||
val key = "key"
|
||||
val blake2b = Blake2b(key)
|
||||
blake2b.update(test)
|
||||
val result = blake2b.digest()
|
||||
|
||||
assertTrue {
|
||||
result.isNotEmpty()
|
||||
}
|
||||
val expectedResult = ("5c6a9a4ae911c02fb7e71a991eb9aea371ae993d4842d206e" +
|
||||
"6020d46f5e41358c6d5c277c110ef86c959ed63e6ecaaaceaaff38019a43264ae06acf73b9550b1")
|
||||
.chunked(2).map { it.toUByte(16) }.toTypedArray()
|
||||
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1603
File diff suppressed because it is too large.
Load diff
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.sha
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 17-Jul-2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
class Sha256Test {
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownValue() {
|
||||
|
||||
val result = Sha256.digest(message = "abc")
|
||||
val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownDoubleBlock() {
|
||||
|
||||
val resultDoubleBlock = Sha256.digest(message = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
|
||||
val expectedResultForDoubleBlock = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
|
||||
assertTrue {
|
||||
resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.sha
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 17-Jul-2019
|
||||
*/
|
||||
class Sha512Test {
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownValue() {
|
||||
|
||||
val result = Sha512.digest(message = "abc".encodeToByteArray().map { it.toUByte() }.toTypedArray())
|
||||
println(result.map {it.toString(16)})
|
||||
val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownDoubleBlock() {
|
||||
|
||||
val resultDoubleBlock = Sha512.digest(message = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
|
||||
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
|
||||
val expectedResultForDoubleBlock = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" +
|
||||
"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"
|
||||
assertTrue {
|
||||
resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownLong() {
|
||||
val inputBuilder = StringBuilder()
|
||||
for (i in 0 until 1000000) {
|
||||
inputBuilder.append("a")
|
||||
}
|
||||
val resultDoubleBlock = Sha512.digest(message = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toTypedArray())
|
||||
val expectedResultForDoubleBlock = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
|
||||
assertTrue {
|
||||
resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.util
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
expect fun testBlocking(block : suspend (scope : CoroutineScope) -> Unit)
|
||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "kotlin-multiplatform-crypto-js",
|
||||
"version": "0.0.1",
|
||||
"description": "Kotlin Multiplatform Crypto",
|
||||
"main": "crypto.js",
|
||||
"author": "Ugljesa Jovanovic",
|
||||
"license": "Apache 2.0",
|
||||
"homepage": "",
|
||||
"dependencies": {
|
||||
"kotlin": "1.3.40"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "5.2.0"
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.util
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.promise
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
actual fun testBlocking(block: suspend (scope: CoroutineScope) -> Unit) : dynamic = GlobalScope.promise { block(this) }
|
||||
Whitespace-only changes.
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.util
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
actual fun testBlocking(block: suspend (scope: CoroutineScope) -> Unit) = runBlocking { block(this) }
|
||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.ionspin.kotlin.crypto.util
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
actual fun testBlocking(block: suspend (scope: CoroutineScope) -> Unit) = runBlocking { block(this) }
|
||||
Whitespace-only changes.
Reference in new issue
Block a user