From 781c9c1b615c770f17d91df4056e3522af20569e Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Wed, 27 May 2020 23:49:08 +0200 Subject: [PATCH] Working js libsodium, need to change apis to suspend --- buildSrc/src/main/kotlin/Deps.kt | 4 +-- gradle.properties | 1 + .../ionspin/kotlin/crypto/CryptoProvider.kt | 12 +++++++ .../com/ionspin/kotlin/crypto/hash/Hash.kt | 2 +- .../crypto/{CryptoProvider.kt => Crypto.kt} | 14 +++++++- .../kotlin/crypto/hash/sha/Sha256Pure.kt | 2 +- .../kotlin/crypto/hash/sha/Sha512Pure.kt | 2 +- .../com/ionspin/kotlin/crypto/Initializer.kt | 25 ++++++++++++++ .../kotlin/crypto/JsSodiumInterface.kt | 10 ++++++ .../ionspin/kotlin/crypto/JsSodiumLoader.kt | 33 +++++++++++++++++++ .../crypto/hash/blake2b/Blake2bDelegated.kt | 27 ++++++++------- .../src/jsMain/kotlin/libsodium.kt | 15 +++++++-- .../crypto/hash/blake2b/Blake2bJsTest.kt | 10 +++++- .../com/ionspin/kotlin/crypto/Initializer.kt | 6 ++++ .../crypto/hash/blake2b/Blake2bDelegated.kt | 2 +- .../com/ionspin/kotlin/crypto/Initializer.kt | 6 ++++ .../crypto/hash/blake2b/Blake2bDelegated.kt | 2 +- .../kotlin/crypto/hash/blake2b/Blake2bPure.kt | 2 +- .../kotlin/crypto/hash/sha/Sha256Pure.kt | 2 +- .../kotlin/crypto/hash/sha/Sha512Pure.kt | 2 +- 20 files changed, 153 insertions(+), 26 deletions(-) create mode 100644 multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt rename multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/{CryptoProvider.kt => Crypto.kt} (60%) create mode 100644 multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt create mode 100644 multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt create mode 100644 multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumLoader.kt create mode 100644 multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt create mode 100644 multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt index fd3f694..490a656 100644 --- a/buildSrc/src/main/kotlin/Deps.kt +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -50,8 +50,8 @@ object Deps { val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:${Versions.kotlinSerialization}" object Npm { - val libsodium = Pair("libsodium", "0.7.6") - val libsodiumWrappers = Pair("libsodium-wrappers", "0.7.6") + val libsodium = Pair("libsodium-sumo", "0.7.6") + val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "0.7.6") } } diff --git a/gradle.properties b/gradle.properties index f90245d..23b620c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,6 +18,7 @@ org.gradle.parallel=true kotlin.code.style=official kotlin.js.compiler=ir +#kotlin.js.experimental.generateKotlinExternals=true kotlin.mpp.enableGranularSourceSetsMetadata=true org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=4096m diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt new file mode 100644 index 0000000..e836850 --- /dev/null +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt @@ -0,0 +1,12 @@ +package com.ionspin.kotlin.crypto + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 27-May-2020 + */ +interface CryptoProvider { + suspend fun initialize() + + +} \ No newline at end of file diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt index 327556a..a04dbad 100644 --- a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/Hash.kt @@ -39,7 +39,7 @@ interface UpdatableHash : Hash { @ExperimentalUnsignedTypes interface StatelessHash : Hash { - fun digest(inputString: String, key: String? = null, hashLength: Int = MAX_HASH_BYTES): UByteArray + suspend fun digest(inputString: String, key: String? = null, hashLength: Int = MAX_HASH_BYTES): UByteArray fun digest( inputMessage: UByteArray = ubyteArrayOf(), diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/Crypto.kt similarity index 60% rename from multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt rename to multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/Crypto.kt index fb757dd..85f8a14 100644 --- a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/CryptoProvider.kt +++ b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/Crypto.kt @@ -12,4 +12,16 @@ import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure typealias Sha256Stateless = Sha256Pure.Companion -typealias Sha512Stateless = Sha512Pure.Companion \ No newline at end of file +typealias Sha512Stateless = Sha512Pure.Companion + +object Crypto : CryptoProvider { + override suspend fun initialize() { + Initializer.initialize() + } + +} + +expect object Initializer { + suspend fun initialize() +} + diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt index ec646c1..27eb1d4 100644 --- a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt +++ b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt @@ -66,7 +66,7 @@ class Sha256Pure : Sha256 { ) @ExperimentalStdlibApi - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { return digest( inputString.encodeToByteArray().toUByteArray(), key?.run { encodeToByteArray().toUByteArray()} ?: ubyteArrayOf(), diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt index 955ee61..6c3725f 100644 --- a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt +++ b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt @@ -134,7 +134,7 @@ class Sha512Pure : Sha512 { ) @ExperimentalStdlibApi - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { return digest( inputString.encodeToByteArray().toUByteArray(), key?.run { encodeToByteArray().toUByteArray() } ?: ubyteArrayOf(), diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt new file mode 100644 index 0000000..a2ef6a6 --- /dev/null +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt @@ -0,0 +1,25 @@ +package com.ionspin.kotlin.crypto + +import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface +import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader +/* 1.4-M1 has some weirdness with static/objects, or I'm misusing something, not sure */ +lateinit var sodiumPointer : JsSodiumInterface +var sodiumLoaded: Boolean = false + +fun getSodiumPointer() : JsSodiumInterface = sodiumPointer + +fun setSodiumPointer(jsSodiumInterface: JsSodiumInterface) { + js("sodiumPointer = jsSodiumInterface") +} + +fun getSodiumLoaded() : Boolean = sodiumLoaded + +fun setSodiumLoaded(loaded: Boolean) { + js("sodiumLoaded = loaded") +} + +actual object Initializer { + actual suspend fun initialize() { + JsSodiumLoader.load() + } +} \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt new file mode 100644 index 0000000..3a85c15 --- /dev/null +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt @@ -0,0 +1,10 @@ +package ext.libsodium.com.ionspin.kotlin.crypto + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 27-May-2020 + */ +interface JsSodiumInterface { + fun crypto_generichash(hashLength: Int, inputMessage: String) : String +} \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumLoader.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumLoader.kt new file mode 100644 index 0000000..d4bef22 --- /dev/null +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumLoader.kt @@ -0,0 +1,33 @@ +package ext.libsodium.com.ionspin.kotlin.crypto + +import com.ionspin.kotlin.crypto.getSodiumLoaded +import com.ionspin.kotlin.crypto.getSodiumPointer +import com.ionspin.kotlin.crypto.setSodiumPointer +import com.ionspin.kotlin.crypto.sodiumLoaded +import ext.libsodium._libsodiumPromise +import kotlin.coroutines.Continuation +import kotlin.coroutines.suspendCoroutine + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 27-May-2020 + */ +object JsSodiumLoader { + + fun storeSodium(promisedSodium: dynamic, continuation: Continuation) { + setSodiumPointer(promisedSodium) + sodiumLoaded = true + continuation.resumeWith(Result.success(getSodiumPointer())) + } + + suspend fun load(): JsSodiumInterface = suspendCoroutine { continuation -> + console.log(getSodiumLoaded()) + if (!getSodiumLoaded()) { + val libsodiumModule = js("\$module\$libsodium_wrappers_sumo") + _libsodiumPromise.then { storeSodium(libsodiumModule, continuation) } + } else { + continuation.resumeWith(Result.success(getSodiumPointer())) + } + } +} \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt index bde45d0..590b770 100644 --- a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt @@ -1,9 +1,9 @@ package com.ionspin.kotlin.crypto.hash.blake2b -import crypto_generichash -import org.khronos.webgl.Uint8Array -import org.khronos.webgl.get -import kotlin.js.Promise +import com.ionspin.kotlin.crypto.util.toHexString +import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface +import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader +import ext.libsodium.crypto_generichash /** * Created by Ugljesa Jovanovic @@ -38,12 +38,18 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: I actual object Blake2bStateless : Blake2bStatelessInterface { override val MAX_HASH_BYTES: Int = 64 - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { -// val hashed = crypto_generichash(64, Uint8Array(inputString.encodeToByteArray().toTypedArray()), null) -// return UByteArray(MAX_HASH_BYTES) { hashed[it].toUByte() } - - val hash = crypto_generichash(64, Uint8Array(arrayOf(0U.toByte()))); - println("Hash $hash") + override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + val sodium = JsSodiumLoader.load() + val hashed = sodium.crypto_generichash(64, inputString) + val hash = UByteArray(MAX_HASH_BYTES) + for (i in 0 until MAX_HASH_BYTES) { + js( + """ + hash[i] = hashed[i] + """ + ) + } + println("Hash ${hash.toHexString()}") return ubyteArrayOf(0U) } @@ -52,5 +58,4 @@ actual object Blake2bStateless : Blake2bStatelessInterface { } - } \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/libsodium.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/libsodium.kt index d259753..6424781 100644 --- a/multiplatform-crypto-delegated/src/jsMain/kotlin/libsodium.kt +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/libsodium.kt @@ -1,10 +1,19 @@ +@file:JsModule("libsodium-wrappers-sumo") +@file:JsNonModule +package ext.libsodium + import org.khronos.webgl.Uint8Array +import kotlin.js.Promise + /** * Created by Ugljesa Jovanovic * ugljesa.jovanovic@ionspin.com * on 25-May-2020 */ -@JsModule("libsodium") -@JsNonModule -external fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array) : Uint8Array \ No newline at end of file + +@JsName("ready") +external val _libsodiumPromise : Promise + +external fun crypto_generichash(hashLength: Int, inputMessage: String) : String + diff --git a/multiplatform-crypto-delegated/src/jsTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bJsTest.kt b/multiplatform-crypto-delegated/src/jsTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bJsTest.kt index 710c035..d727566 100644 --- a/multiplatform-crypto-delegated/src/jsTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bJsTest.kt +++ b/multiplatform-crypto-delegated/src/jsTest/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bJsTest.kt @@ -1,5 +1,8 @@ package com.ionspin.kotlin.crypto.hash.blake2b +import com.ionspin.kotlin.crypto.Crypto +import com.ionspin.kotlin.crypto.util.testBlocking +import kotlin.test.BeforeTest import kotlin.test.Test /** @@ -11,8 +14,13 @@ import kotlin.test.Test @ExperimentalStdlibApi class Blake2bJsTest { + @BeforeTest + fun setup() = testBlocking { + Crypto.initialize() + } + @Test - fun testBlake2BSodiumInterop() { + fun testBlake2BSodiumInterop() = testBlocking { Blake2bStateless.digest("test") } } \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt b/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt new file mode 100644 index 0000000..e53ffa4 --- /dev/null +++ b/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt @@ -0,0 +1,6 @@ +package com.ionspin.kotlin.crypto + +actual object Initializer { + actual suspend fun initialize() { + } +} \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt b/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt index b15cc5f..7c03af0 100644 --- a/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt +++ b/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt @@ -29,7 +29,7 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: I } @ExperimentalUnsignedTypes actual object Blake2bStateless : Blake2bStatelessInterface { - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + suspend override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { TODO("not implemented yet") } diff --git a/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt b/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt new file mode 100644 index 0000000..e53ffa4 --- /dev/null +++ b/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/Initializer.kt @@ -0,0 +1,6 @@ +package com.ionspin.kotlin.crypto + +actual object Initializer { + actual suspend fun initialize() { + } +} \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt b/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt index 540153e..7f49a0c 100644 --- a/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt +++ b/multiplatform-crypto-delegated/src/linuxMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bDelegated.kt @@ -34,7 +34,7 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: I @Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") actual object Blake2bStateless : Blake2bStatelessInterface { - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + suspend override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { val hashResult = UByteArray(MAX_HASH_BYTES) val hashResultPinned = hashResult.pin() crypto_generichash( diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt index 5ad92b8..a60bcb2 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2bPure.kt @@ -145,7 +145,7 @@ class Blake2bPure(val key: UByteArray? = null, val hashLength: Int = 64) : Blake } @ExperimentalStdlibApi - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { val array = inputString.encodeToByteArray().toUByteArray() val keyBytes = key?.run { encodeToByteArray().toUByteArray() diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt index ec646c1..7bbb4a4 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha256Pure.kt @@ -66,7 +66,7 @@ class Sha256Pure : Sha256 { ) @ExperimentalStdlibApi - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + suspend override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { return digest( inputString.encodeToByteArray().toUByteArray(), key?.run { encodeToByteArray().toUByteArray()} ?: ubyteArrayOf(), diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt index 955ee61..6c3725f 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/sha/Sha512Pure.kt @@ -134,7 +134,7 @@ class Sha512Pure : Sha512 { ) @ExperimentalStdlibApi - override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { + override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { return digest( inputString.encodeToByteArray().toUByteArray(), key?.run { encodeToByteArray().toUByteArray() } ?: ubyteArrayOf(),