commonMain.io.eqoty.secretk.utils.EnigmaUtils.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of client-jvm Show documentation
Show all versions of client-jvm Show documentation
A Kotlin multiplatform REST client utilizing secret network's gRPC gateway endpoints.
package io.eqoty.secretk.utils
import com.ionspin.kotlin.crypto.util.LibsodiumRandom
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import io.eqoty.secretk.crypto.AesSIV
import io.eqoty.secretk.crypto.deriveHKDFKey
import io.eqoty.secretk.utils.AxlSign.generateKeyPair
import io.eqoty.secretk.utils.AxlSign.sharedKey
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.util.*
import kotlinx.coroutines.Deferred
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
@Serializable
data class Result(val TxKey: String)
@Serializable
data class TxKeyResponse(val height: Int, val result: Result)
data class KeyPair(val privKey: UByteArray, val pubKey: UByteArray)
class EnigmaUtils internal constructor(val apiUrl: String, val seed: UByteArray) : EncryptionUtils {
val hkdfSalt = ubyteArrayOf(
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x00.toUByte(),
0x02.toUByte(),
0x4b.toUByte(),
0xea.toUByte(),
0xd8.toUByte(),
0xdf.toUByte(),
0x69.toUByte(),
0x99.toUByte(),
0x08.toUByte(),
0x52.toUByte(),
0xc2.toUByte(),
0x02.toUByte(),
0xdb.toUByte(),
0x0e.toUByte(),
0x00.toUByte(),
0x97.toUByte(),
0xc1.toUByte(),
0xa1.toUByte(),
0x2e.toUByte(),
0xa6.toUByte(),
0x37.toUByte(),
0xd7.toUByte(),
0xe9.toUByte(),
0x6d.toUByte(),
)
private val siv = AesSIV()
private val privKey: UByteArray
val pubKey: UByteArray
init {
if (seed.size != 32) {
throw Error("encryptionSeed must be a UByteArray of length 32")
}
val keyPair = GenerateNewKeyPairFromSeed(this.seed)
this.privKey = keyPair.privKey
this.pubKey = keyPair.pubKey
}
companion object {
suspend fun init(apiUrl: String, seed: UByteArray?): EnigmaUtils {
ensureLibsodiumInitialized()
return EnigmaUtils(apiUrl, seed ?: GenerateNewSeed())
}
suspend fun GenerateNewKeyPair(): KeyPair {
return GenerateNewKeyPairFromSeed(GenerateNewSeed())
}
suspend fun GenerateNewSeed(): UByteArray {
ensureLibsodiumInitialized()
return LibsodiumRandom.buf(32)
}
fun GenerateNewKeyPairFromSeed(seed: UByteArray): KeyPair {
val keys = generateKeyPair(seed.toIntArray())
return KeyPair(
keys.privateKey.toUByteArray(),
keys.publicKey.toUByteArray()
)
}
}
private val client: HttpClient = HttpClient {
install(DefaultRequest) {
contentType(ContentType.Application.Json)
}
install(ContentNegotiation) {
json(Json)
}
}
private var consensusIoPubKey: UByteArray? = null // cache
private suspend fun getConsensusIoPubKey(): UByteArray {
if (this.consensusIoPubKey != null) {
return this.consensusIoPubKey!!
}
val txKeyResponse: TxKeyResponse = client.get(this.apiUrl + "/reg/tx-key").body()
val txKey = txKeyResponse.result.TxKey.decodeBase64Bytes()
this.consensusIoPubKey = txKey.toUByteArray()
return this.consensusIoPubKey!!
}
override suspend fun getPubkey(): Deferred {
TODO("Not yet implemented")
}
override suspend fun decrypt(ciphertext: UByteArray, nonce: UByteArray): UByteArray {
if (ciphertext.isEmpty()) {
return ubyteArrayOf()
}
val txEncryptionKey = getTxEncryptionKey(nonce)
//console.log(`decrypt tx encryption key: ${Encoding.toHex(txEncryptionKey)}`);
val plaintext = siv.decrypt(txEncryptionKey, ciphertext, ubyteArrayOf())
return plaintext
}
override suspend fun encrypt(contractCodeHash: String, message: JsonObject): UByteArray {
val nonce = LibsodiumRandom.buf(32)
val txEncryptionKey = getTxEncryptionKey(nonce)
val plaintext = contractCodeHash + message
val ciphertext = siv.encrypt(txEncryptionKey, plaintext.encodeToUByteArray(), ubyteArrayOf())
return nonce + this.pubKey + ciphertext
}
override suspend fun getTxEncryptionKey(nonce: UByteArray): UByteArray {
val consensusIoPubKey = getConsensusIoPubKey()
val txEncryptionIkm = sharedKey(this.privKey.toIntArray(), consensusIoPubKey.toIntArray()).toUByteArray()
return deriveHKDFKey(txEncryptionIkm + nonce, hkdfSalt, len = 32)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy