Does anyone know how I can pick select crypto from...
# webassembly
l
Does anyone know how I can pick select crypto from either
window.crypto
on browser or node
crypto
for node on the wasmJs target? This works on for the js target. But in the wasmJs target I can only get it to work correctly for one at a time.
Copy code
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import org.khronos.webgl.ArrayBufferView

external interface WebCrypto {
    fun <T : ArrayBufferView> getRandomValues(array: T): T
}

// For node
@JsModule("crypto")
external val webcrypto: WebCrypto

// For browser
external object window {
    val crypto: WebCrypto
}

actual class SecureRandom {
    var crypto: WebCrypto? = null

    init {
        crypto =
            try {
                // browser
                window.crypto
            } catch (_: Throwable) {
                null
            }
        if (crypto == null) {
            try {
                // node
                crypto = webcrypto
            } catch (_: Throwable) {
            }
        }
        requireNotNull(crypto) { "Could not get crypto from window or node" }
    }

    actual fun nextBytes(bytes: ByteArray) {
        val uint8bytes = Uint8Array(bytes.size)
        crypto!!.getRandomValues(uint8bytes)
        for (i in bytes.indices) {
            bytes[i] = uint8bytes[i]
        }
    }
}
To get it to work for node I need to comment out:
Copy code
crypto =
            try {
                // browser
                window.crypto
            } catch (_: Throwable) {
                null
            }
and respectively to get it to work for browser I need to comment out:
Copy code
if (crypto == null) {
            try {
                // node
                crypto = webcrypto
            } catch (_: Throwable) {
            }
        }
Running node tests without commenting out the
window.crypto
part will throw:
Copy code
ReferenceError: window is not defined
      at jslibs.window_$external_object_getInstance
Also, is this possible on the wasmJs target?
unsafeCast
doesn’t seem to let you do this unlike the
unsafeCast
on the js target
Copy code
fun Uint8Array.asByteArray(): ByteArray = this.unsafeCast<ByteArray>()
fun ByteArray.asUint8Array(): Uint8Array = this.unsafeCast<Uint8Array>()
o
l
Thanks for the reference! @Oleg Yukhnevich however I just tried that and I’m running into an issue I was having earlier when I tried something similar:
Copy code
Calls to js(code) should be a single expression inside a top-level function body or a property initializer in Kotlin/Wasm
I’ve been getting that error pretty much every time I try to do anything with
js("…")
on the wasm target
o
on wasm
js("...")
has a lot of restrictions (https://kotlinlang.org/docs/wasm-js-interop.html#kotlin-functions-with-javascript-code) But at least this variant, that I've posted above works with Kotlin 1.9.20 By this variant I mean not only code inside
js("...")
but also where it's placed:
Copy code
// js(...) should be single declaration in a function, should not be an expression, just a statement
fun getCrypto(): Crypto {
    js(
        code = """
    
        var isNodeJs = typeof process !== 'undefined' && process.versions != null && process.versions.node != null
        if (isNodeJs) {
            return (eval('require')('node:crypto').webcrypto);
        } else {
            return (window ? (window.crypto ? window.crypto : window.msCrypto) : self.crypto);
        }
    
               """
    )
}
l
Ohh I see now. I glossed over that error explaination saying it needs to be a top level function. I moved
fun getCrypto(): Crypto
out of my class and you’re right it does work!
Thanks alot! @Oleg Yukhnevich
o
glad it's helped 🙂
🙏 1
l
I was actually briefly looking at your cryptography-kotlin lib today see if wasm was supported, but didn’t go through all your branches. is there a release with wasm targets out already?
o
Not yet. next release is planned in coming weeks (it will support Random for WasmJs and WasmWasi + WebCrypto provider for WasmJs)
🔥 1
l
@Oleg Yukhnevich Sweet. Looking forward to trying it out! I’m in the process of updating a blockchain client I wrote with wasm support, and I’m thinking I should switch to using your lib for signing with ecdsa… vs the hacked port of https://github.com/indutny/elliptic I threw together here haha
o
You can try it even right now if you want, snapshot build already contains Wasm things (published from
dev
branch) to try snapshot: https://github.com/whyoleg/cryptography-kotlin?tab=readme-ov-file#using-in-your-projects (under a drop-down)
👍 1
l
Nice I’ll take a look