From 1f0eaf59ca67701947bbb23bcdc43ab95251fd35 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 8 Aug 2020 16:20:56 +0200 Subject: [PATCH] Pivot to a handled API, update common js and native generators --- .../libsodium/definitions/DefinitionTypes.kt | 51 +++++- .../definitions/LibsodiumDefinitions.kt | 78 +-------- .../LibsodiumGenericHashDefinitions.kt | 37 ++++ .../definitions/LibsodiumHashDefinitions.kt | 80 +++++++++ .../generator/CommonLibsodiumGenerator.kt | 20 ++- .../generator/JsLibsodiumGenerator.kt | 95 ++++++----- .../generator/JvmLibsodiumGenerator.kt | 55 +++--- .../generator/NativeLibsodiumGenerator.kt | 159 +++++++++++++----- .../commonMain/kotlin/debug/test/DebugTest.kt | 14 +- .../src/jsMain/kotlin/debug/test/DebugTest.kt | 29 ++-- .../jvmMain/kotlin/debug/test/DebugTest.kt | 14 +- .../nativeMain/kotlin/debug/test/DebugTest.kt | 45 +++-- 12 files changed, 419 insertions(+), 258 deletions(-) create mode 100644 kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumGenericHashDefinitions.kt create mode 100644 kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumHashDefinitions.kt diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/DefinitionTypes.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/DefinitionTypes.kt index 2994257..3036706 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/DefinitionTypes.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/DefinitionTypes.kt @@ -35,9 +35,13 @@ class ClassDefinition( operator fun FunctionDefinition.unaryPlus() { methods.add(this) } + + operator fun List.unaryPlus() { + methods.addAll(this) + } } -class InnerClassDefinition ( +class InnerClassDefinition( val name: String, val javaName: String, val jsName: String, @@ -51,7 +55,10 @@ class FunctionDefinition( val jsName: String, val nativeName: String, val parameterList: MutableList = mutableListOf(), - val returnType: GeneralTypeDefinition + val returnType: GeneralTypeDefinition, + val dynamicJsReturn: Boolean = false, + val isStateCreationFunction: Boolean = false, + val outputLengthWhenArray: Int = -1 ) { operator fun ParameterDefinition.unaryPlus() { parameterList.add(this) @@ -61,11 +68,14 @@ class FunctionDefinition( class ParameterDefinition( val parameterName: String, val parameterType: GeneralTypeDefinition, - val modifiesReturn: Boolean = false + val modifiesReturn: Boolean = false, + val isActuallyAnOutputParam: Boolean = false, + val isStateType: Boolean = false, + val dropParameterFromDefinition: Boolean = false, ) interface GeneralTypeDefinition { - val typeName : TypeName + val typeName: TypeName } data class CustomTypeDefinition(override val typeName: TypeName) : GeneralTypeDefinition @@ -80,7 +90,7 @@ enum class TypeDefinition(override val typeName: TypeName) : GeneralTypeDefiniti UNIT(Unit::class.asTypeName()) } -fun fileDef(name: String, body: KotlinFileDefinition.() -> Unit) : KotlinFileDefinition { +fun fileDef(name: String, body: KotlinFileDefinition.() -> Unit): KotlinFileDefinition { val commonKotlinFileInstance = KotlinFileDefinition(name) commonKotlinFileInstance.body() return commonKotlinFileInstance @@ -99,7 +109,7 @@ fun innerClassDef( jsName: String, nativeName: String, body: InnerClassDefinition.() -> Unit = {} -) : InnerClassDefinition { +): InnerClassDefinition { val genClass = InnerClassDefinition( name, javaName, @@ -116,9 +126,21 @@ fun funcDef( jsName: String, nativeName: String, returnType: GeneralTypeDefinition, + dynamicJsReturn: Boolean = false, + isStateCreationFunction: Boolean = false, + outputLengthWhenArray: Int = -1, body: FunctionDefinition.() -> Unit ): FunctionDefinition { - val function = FunctionDefinition(name, javaName, jsName, nativeName, returnType = returnType) + val function = FunctionDefinition( + name, + javaName, + jsName, + nativeName, + returnType = returnType, + dynamicJsReturn = dynamicJsReturn, + isStateCreationFunction = isStateCreationFunction, + outputLengthWhenArray = outputLengthWhenArray + ) function.body() return function } @@ -126,9 +148,22 @@ fun funcDef( fun funcDef( name: String, returnType: GeneralTypeDefinition, + dynamicJsReturn: Boolean = false, + isStateCreationFunction: Boolean = false, + outputLengthWhenArray: Int = -1, body: FunctionDefinition.() -> Unit ): FunctionDefinition { - val function = FunctionDefinition(name, name, name, name, returnType = returnType) + val function = + FunctionDefinition( + name, + name, + name, + name, + returnType = returnType, + dynamicJsReturn = dynamicJsReturn, + isStateCreationFunction = isStateCreationFunction, + outputLengthWhenArray = outputLengthWhenArray + ) function.body() return function } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumDefinitions.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumDefinitions.kt index 1dd0229..61cacf0 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumDefinitions.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumDefinitions.kt @@ -8,82 +8,8 @@ package com.ionspin.kotlin.crypto.generator.libsodium.definitions object LibSodiumDefinitions { val testKotlinFile = fileDef("DebugTest") { +classDef("Crypto") { - - /* - --------------- SHA256 - */ - +innerClassDef( - "Sha256State", - "com.goterl.lazycode.lazysodium.interfaces.Hash.State256", - "Sha256State", - "crypto_hash_sha256_state" - ) - +funcDef( - "crypto_hash_sha256_init", - TypeDefinition.INT - ) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha256State")))) - } - - +funcDef("crypto_hash_sha256_update", TypeDefinition.UNIT) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha256State")))) - +ParameterDefinition("input", TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE) - } - - +funcDef("crypto_hash_sha256_final", TypeDefinition.UNIT) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha256State")))) - +ParameterDefinition("out", TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE) - } - - /* - --------------- SHA512 - */ - +innerClassDef( - "Sha512State", - "com.goterl.lazycode.lazysodium.interfaces.Hash.State512", - "Sha512State", - "crypto_hash_sha512_state" - ) - +funcDef( - "crypto_hash_sha512_init", - TypeDefinition.INT - ) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha512State")))) - } - - +funcDef("crypto_hash_sha512_update", TypeDefinition.UNIT) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha512State")))) - +ParameterDefinition("input", TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE) - } - - +funcDef("crypto_hash_sha512_final", TypeDefinition.UNIT) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha512State")))) - +ParameterDefinition("out", TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE) - } - - /* - * ------------- GENERIC HASH (BLAKE2B) - */ - - +innerClassDef( - "GenericHashState", - "ByteArray", - "Uint8Array", - "crypto_generichash_blake2b_state" - ) - - +funcDef( - "crypto_generichash_init", - TypeDefinition.INT - ) { - +ParameterDefinition("state", CustomTypeDefinition((withPackageName("GenericHashState")))) - +ParameterDefinition("key", TypeDefinition.ARRAY_OF_UBYTES) - +ParameterDefinition("outlen", TypeDefinition.INT, modifiesReturn = true) - } - - + defineHashFunctions() + defineGenericHashFunctions() } - - } } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumGenericHashDefinitions.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumGenericHashDefinitions.kt new file mode 100644 index 0000000..1aec8e6 --- /dev/null +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumGenericHashDefinitions.kt @@ -0,0 +1,37 @@ +package com.ionspin.kotlin.crypto.generator.libsodium.definitions + +import com.squareup.kotlinpoet.ClassName + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 04-Aug-2020 + */ +fun ClassDefinition.defineGenericHashFunctions() { + /* + * ------------- GENERIC HASH (BLAKE2B) + */ + + +innerClassDef( + "GenericHashState", + "ByteArray", + "Uint8Array", + "crypto_generichash_blake2b_state" + ) + + +funcDef( + "crypto_generichash_init", + CustomTypeDefinition(ClassName(packageName, "GenericHashState")), + true, + isStateCreationFunction = true + ) { + +ParameterDefinition( + "state", + CustomTypeDefinition((withPackageName("GenericHashState"))), + isStateType = true, + dropParameterFromDefinition = true + ) + +ParameterDefinition("key", TypeDefinition.ARRAY_OF_UBYTES) + +ParameterDefinition("outlen", TypeDefinition.INT, modifiesReturn = true) + } +} diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumHashDefinitions.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumHashDefinitions.kt new file mode 100644 index 0000000..b196ecf --- /dev/null +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumHashDefinitions.kt @@ -0,0 +1,80 @@ +package com.ionspin.kotlin.crypto.generator.libsodium.definitions + +import com.squareup.kotlinpoet.ClassName + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 04-Aug-2020 + */ +fun ClassDefinition.defineHashFunctions() { + /* + --------------- SHA256 + */ + +innerClassDef( + "Sha256State", + "com.goterl.lazycode.lazysodium.interfaces.Hash.State256", + "Sha256State", + "crypto_hash_sha256_state" + ) + +funcDef( + "crypto_hash_sha256_init", + CustomTypeDefinition(ClassName(packageName, "Sha256State")), + dynamicJsReturn = true, + isStateCreationFunction = true + ) { + +ParameterDefinition( + "state", + CustomTypeDefinition((withPackageName("Sha256State"))), + dropParameterFromDefinition = true, + isStateType = true + ) + } + + +funcDef("crypto_hash_sha256_update", TypeDefinition.UNIT) { + +ParameterDefinition( + "state", + CustomTypeDefinition((withPackageName("Sha256State"))), + isStateType = true + ) + +ParameterDefinition("input", TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE) + } + + +funcDef("crypto_hash_sha256_final", TypeDefinition.ARRAY_OF_UBYTES, outputLengthWhenArray = 32) { + +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha256State")))) + +ParameterDefinition("out", TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, isActuallyAnOutputParam = true, dropParameterFromDefinition = true) + } + + /* + --------------- SHA512 + */ + +innerClassDef( + "Sha512State", + "com.goterl.lazycode.lazysodium.interfaces.Hash.State512", + "Sha512State", + "crypto_hash_sha512_state" + ) + +funcDef( + "crypto_hash_sha512_init", + CustomTypeDefinition(ClassName(packageName, "Sha512State")), + true, + isStateCreationFunction = true + ) { + +ParameterDefinition( + "state", + CustomTypeDefinition((withPackageName("Sha512State"))), + dropParameterFromDefinition = true, + isStateType = true + ) + } + + +funcDef("crypto_hash_sha512_update", TypeDefinition.UNIT) { + +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha512State")))) + +ParameterDefinition("input", TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE) + } + + +funcDef("crypto_hash_sha512_final", TypeDefinition.ARRAY_OF_UBYTES, outputLengthWhenArray = 64) { + +ParameterDefinition("state", CustomTypeDefinition((withPackageName("Sha512State")))) + +ParameterDefinition("out", TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, isActuallyAnOutputParam = true, dropParameterFromDefinition = true) + } +} diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt index 4fda61d..1ff5af6 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt @@ -51,12 +51,24 @@ object CommonLibsodiumGenerator { fun createCommonMethodSpec(methodDefinition: FunctionDefinition): FunSpec { val methodBuilder = FunSpec.builder(methodDefinition.name) + var actualReturnType : TypeName = Any::class.asTypeName() + var actualReturnTypeFound : Boolean = false for (paramDefinition in methodDefinition.parameterList) { - val parameterSpec = - ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) - methodBuilder.addParameter(parameterSpec.build()) + if ((paramDefinition.isStateType.not() || methodDefinition.isStateCreationFunction.not()) && paramDefinition.dropParameterFromDefinition.not()) { + val parameterSpec = + ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) + methodBuilder.addParameter(parameterSpec.build()) + } + if (paramDefinition.isActuallyAnOutputParam) { + actualReturnTypeFound = true + actualReturnType = paramDefinition.parameterType.typeName + } + } + if (actualReturnTypeFound) { + methodBuilder.returns(actualReturnType) + } else { + methodBuilder.returns(methodDefinition.returnType.typeName) } - methodBuilder.returns(methodDefinition.returnType.typeName) return methodBuilder.build() } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JsLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JsLibsodiumGenerator.kt index 2a1ae5e..a70402d 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JsLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JsLibsodiumGenerator.kt @@ -14,6 +14,7 @@ object JsLibsodiumGenerator { fun createJsFile(packageName: String, fileDefinition: KotlinFileDefinition): FileSpec { val fileBuilder = FileSpec.builder(packageName, fileDefinition.name) fileBuilder.addImport("ext.libsodium.com.ionspin.kotlin.crypto", "toUInt8Array") + fileBuilder.addImport("ext.libsodium.com.ionspin.kotlin.crypto", "toUByteArray") fileBuilder.addImport("com.ionspin.kotlin.crypto", "getSodium") for (commonClassDefinition in fileDefinition.commonClassList) { //Create type-aliases @@ -48,10 +49,14 @@ object JsLibsodiumGenerator { methodBuilder.modifiers += MultiplatformModifier.ACTUAL.modifierList var returnModifierFound = false var returnModifierName = "" + var actualReturnType: TypeName = DYNAMIC + var actualReturnTypeFound: Boolean = false for (paramDefinition in methodDefinition.parameterList) { - val parameterSpec = - ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) - methodBuilder.addParameter(parameterSpec.build()) + if ((paramDefinition.isStateType.not() || methodDefinition.isStateCreationFunction.not()) && paramDefinition.isActuallyAnOutputParam.not()) { + val parameterSpec = + ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) + methodBuilder.addParameter(parameterSpec.build()) + } if (paramDefinition.modifiesReturn) { if (returnModifierFound == true) { throw RuntimeException("Return modifier already found") @@ -59,53 +64,51 @@ object JsLibsodiumGenerator { returnModifierFound = true returnModifierName = paramDefinition.parameterName } + if (paramDefinition.isActuallyAnOutputParam) { + actualReturnTypeFound = true + actualReturnType = paramDefinition.parameterType.typeName + } + } + methodBuilder.addStatement("println(\"Debug\")") + val constructJsCall = StringBuilder() + when (methodDefinition.returnType) { + TypeDefinition.ARRAY_OF_UBYTES -> { + constructJsCall.append("return getSodium().${methodDefinition.javaName}") + constructJsCall.append(paramsToString(methodDefinition) + ".toUByteArray()") + } + TypeDefinition.INT -> { + constructJsCall.append("return getSodium().${methodDefinition.javaName}") + constructJsCall.append(paramsToString(methodDefinition)) + } + TypeDefinition.UNIT -> { + constructJsCall.append("getSodium().${methodDefinition.javaName}") + constructJsCall.append(paramsToString(methodDefinition)) + } + is CustomTypeDefinition -> { + constructJsCall.append("return getSodium().${methodDefinition.javaName}") + constructJsCall.append(paramsToString(methodDefinition)) + } + } + methodBuilder.addStatement(constructJsCall.toString()) + if (actualReturnTypeFound) { + methodBuilder.returns(actualReturnType) + return methodBuilder.build() } - if (methodDefinition.returnType == TypeDefinition.ARRAY_OF_UBYTES) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return getSodium().${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) + if (methodDefinition.dynamicJsReturn) { + methodBuilder.returns(Dynamic) + } else { + methodBuilder.returns(methodDefinition.returnType.typeName) } - - if (methodDefinition.returnType == TypeDefinition.INT) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return getSodium().${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - if (methodDefinition.returnType == TypeDefinition.UNIT) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("getSodium().${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - if (methodDefinition.returnType is CustomTypeDefinition) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return getSodium().${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - methodBuilder.returns(methodDefinition.returnType.typeName) return methodBuilder.build() } - fun paramsToString(methodDefinition: FunctionDefinition) : String { + fun paramsToString(methodDefinition: FunctionDefinition): String { val paramsBuilder = StringBuilder() paramsBuilder.append("(") - methodDefinition.parameterList.forEachIndexed { index, paramDefinition -> - val separator = if (index == methodDefinition.parameterList.size - 1) { + val jsParams = methodDefinition.parameterList.filter { it.dropParameterFromDefinition.not() } + jsParams.forEachIndexed { index, paramDefinition -> + val separator = if (index == jsParams.size - 1) { "" } else { ", " @@ -114,12 +117,12 @@ object JsLibsodiumGenerator { paramsBuilder.append(paramDefinition.parameterName + separator) } if (paramDefinition.parameterType is TypeDefinition) { - when(paramDefinition.parameterType) { + when (paramDefinition.parameterType) { TypeDefinition.ARRAY_OF_UBYTES -> { - paramsBuilder.append(paramDefinition.parameterName + ".toUInt8Array(), " + paramDefinition.parameterName + ".size" + separator) + paramsBuilder.append(paramDefinition.parameterName + ".toUInt8Array()" + separator) } TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { - paramsBuilder.append(paramDefinition.parameterName + ".toUInt8Array(), " + paramDefinition.parameterName + ".size.toLong()" + separator) + paramsBuilder.append(paramDefinition.parameterName + ".toUInt8Array(), " + separator) } TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE -> { paramsBuilder.append(paramDefinition.parameterName + ".toUInt8Array()" + separator) @@ -136,11 +139,11 @@ object JsLibsodiumGenerator { } } + } paramsBuilder.append(')') return paramsBuilder.toString() } - } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt index 32fff5c..d0ba99a 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt @@ -62,42 +62,27 @@ object JvmLibsodiumGenerator { } } - if (methodDefinition.returnType == TypeDefinition.ARRAY_OF_UBYTES) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return sodium.${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) + methodBuilder.addStatement("println(\"Debug\")") + val constructJvmCall = StringBuilder() + when (methodDefinition.returnType) { + TypeDefinition.ARRAY_OF_UBYTES -> { + constructJvmCall.append("return sodium.${methodDefinition.nativeName}") + constructJvmCall.append(paramsToString(methodDefinition)) + } + TypeDefinition.INT -> { + constructJvmCall.append("return sodium.${methodDefinition.nativeName}") + constructJvmCall.append(paramsToString(methodDefinition)) + } + TypeDefinition.UNIT -> { + constructJvmCall.append("sodium.${methodDefinition.nativeName}") + constructJvmCall.append(paramsToString(methodDefinition)) + } + is CustomTypeDefinition -> { + constructJvmCall.append("return sodium.${methodDefinition.nativeName}") + constructJvmCall.append(paramsToString(methodDefinition)) + } } - - if (methodDefinition.returnType == TypeDefinition.INT) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return sodium.${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - if (methodDefinition.returnType == TypeDefinition.UNIT) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("sodium.${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - if (methodDefinition.returnType is CustomTypeDefinition) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return sodium.${methodDefinition.javaName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - + methodBuilder.addStatement(constructJvmCall.toString()) methodBuilder.returns(methodDefinition.returnType.typeName) return methodBuilder.build() } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt index 98050c7..756821d 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt @@ -1,7 +1,19 @@ package com.ionspin.kotlin.crypto.generator.libsodium.generator -import com.ionspin.kotlin.crypto.generator.libsodium.definitions.* -import com.squareup.kotlinpoet.* +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.CustomTypeDefinition +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.FunctionDefinition +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.InnerClassDefinition +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.KotlinFileDefinition +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.ParameterDefinition +import com.ionspin.kotlin.crypto.generator.libsodium.definitions.TypeDefinition +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.FileSpec +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.ParameterSpec +import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.TypeAliasSpec +import com.squareup.kotlinpoet.asTypeName /** * Created by Ugljesa Jovanovic @@ -18,6 +30,9 @@ object NativeLibsodiumGenerator { fileBuilder.addImport("kotlinx.cinterop", "ptr") fileBuilder.addImport("kotlinx.cinterop", "pin") fileBuilder.addImport("kotlinx.cinterop", "addressOf") + fileBuilder.addImport("kotlinx.cinterop", "reinterpret") + fileBuilder.addImport("kotlinx.cinterop", "pointed") + fileBuilder.addImport("libsodium", "sodium_malloc") for (commonClassDefinition in fileDefinition.commonClassList) { //Create type-aliases @@ -33,7 +48,7 @@ object NativeLibsodiumGenerator { //Workarounds for native not emitting types val byteEmitter = PropertySpec.builder("_emitByte", Byte::class.asTypeName()) byteEmitter.initializer(CodeBlock.of("0")) - val byteArrayEmitter = PropertySpec.builder("_emitByteArray", Byte::class.asTypeName()) + val byteArrayEmitter = PropertySpec.builder("_emitByteArray", ByteArray::class.asTypeName()) byteArrayEmitter.initializer(CodeBlock.of("ByteArray(0) {}")) commonClassSpec.addProperty(byteEmitter.build()) commonClassSpec.addProperty(byteArrayEmitter.build()) @@ -60,10 +75,17 @@ object NativeLibsodiumGenerator { methodBuilder.modifiers += MultiplatformModifier.ACTUAL.modifierList var returnModifierFound = false var returnModifierName = "" + lateinit var actualReturnParameterDefinition: ParameterDefinition + var actualReturnTypeFound: Boolean = false for (paramDefinition in methodDefinition.parameterList) { - val parameterSpec = - ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) - methodBuilder.addParameter(parameterSpec.build()) + if (paramDefinition.isStateType && methodDefinition.isStateCreationFunction) { + createStateParam(paramDefinition, methodBuilder) + } + if ((paramDefinition.isStateType.not() || methodDefinition.isStateCreationFunction.not()) && paramDefinition.isActuallyAnOutputParam.not()) { + val parameterSpec = + ParameterSpec.builder(paramDefinition.parameterName, paramDefinition.parameterType.typeName) + methodBuilder.addParameter(parameterSpec.build()) + } if (paramDefinition.modifiesReturn) { if (returnModifierFound == true) { throw RuntimeException("Return modifier already found") @@ -71,52 +93,103 @@ object NativeLibsodiumGenerator { returnModifierFound = true returnModifierName = paramDefinition.parameterName } + if (paramDefinition.isActuallyAnOutputParam) { + actualReturnParameterDefinition = paramDefinition + actualReturnTypeFound = true + } + } + if (actualReturnTypeFound) { + if (returnModifierFound) { + createOutputParam(actualReturnParameterDefinition, returnModifierName, methodBuilder) + } else { + if (methodDefinition.outputLengthWhenArray == -1) { + throw RuntimeException("Function definition lacks a way to define output array length, function ${methodDefinition.name}") + } + createOutputParam(actualReturnParameterDefinition, methodDefinition.outputLengthWhenArray.toString(), methodBuilder) + } } - pinParams(methodDefinition, methodBuilder) - - if (methodDefinition.returnType == TypeDefinition.ARRAY_OF_UBYTES) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return libsodium.${methodDefinition.nativeName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - if (methodDefinition.returnType == TypeDefinition.INT) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return libsodium.${methodDefinition.nativeName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - if (methodDefinition.returnType == TypeDefinition.UNIT) { - - val constructNativeCall = StringBuilder() + val constructNativeCall = StringBuilder() + if (methodDefinition.isStateCreationFunction) { constructNativeCall.append("libsodium.${methodDefinition.nativeName}") constructNativeCall.append(paramsToString(methodDefinition)) - methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement("return state") + } else if (actualReturnTypeFound) { + constructNativeCall.append("libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement("return out") + } else { + when (methodDefinition.returnType) { + TypeDefinition.ARRAY_OF_UBYTES -> { + constructNativeCall.append("val result = libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement("return result") + } + TypeDefinition.INT -> { + constructNativeCall.append("val result = libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement("return result") + } + TypeDefinition.UNIT -> { + constructNativeCall.append("libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + } + is CustomTypeDefinition -> { + constructNativeCall.append("val result = libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement("return result") + } + } + + } - if (methodDefinition.returnType is CustomTypeDefinition) { - methodBuilder.addStatement("println(\"Debug\")") - val constructJvmCall = StringBuilder() - constructJvmCall.append("return libsodium.${methodDefinition.nativeName}") - constructJvmCall.append(paramsToString(methodDefinition)) - - methodBuilder.addStatement(constructJvmCall.toString()) - } - - unpinParams(methodDefinition, methodBuilder) - methodBuilder.returns(methodDefinition.returnType.typeName) + return methodBuilder.build() } + fun createStateParam(stateParameterDefinition: ParameterDefinition, methodBuilder: FunSpec.Builder) { + /* + val allocated = sodium_malloc(crypto_hash_sha256_state.size.convert())!! + state = allocated.reinterpret().pointed + */ + methodBuilder.addStatement("val allocated = sodium_malloc(${stateParameterDefinition.parameterType.typeName}.size.convert())!!") + methodBuilder.addStatement("val state = allocated.reinterpret<${stateParameterDefinition.parameterType.typeName}>().pointed") + } + + fun createOutputParam(outputParam: ParameterDefinition, length: String?, methodBuilder: FunSpec.Builder) { + /* + val hashResult = UByteArray(Sha256Properties.MAX_HASH_BYTES) + val hashResultPinned = hashResult.pin() + crypto_hash_sha256_final(state.ptr, hashResultPinned.addressOf(0)) + sodium_free(state.ptr) + return hashResult + */ + when (outputParam.parameterType) { + TypeDefinition.ARRAY_OF_UBYTES, TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { + methodBuilder.addStatement("val out = UByteArray($length)") + } + else -> { + throw RuntimeException("Unhandled native output param type: ${outputParam.parameterType.typeName}") + } + + + } + } + fun pinParams(methodDefinition: FunctionDefinition, methodBuilder: FunSpec.Builder) { methodDefinition.parameterList.forEachIndexed { index, paramDefinition -> if (paramDefinition.parameterType is TypeDefinition) { @@ -188,10 +261,10 @@ object NativeLibsodiumGenerator { if (paramDefinition.parameterType is TypeDefinition) { when (paramDefinition.parameterType) { TypeDefinition.ARRAY_OF_UBYTES -> { - paramsBuilder.append("pinned" + paramDefinition.parameterName.capitalize() + ".addressOf(0), "+ paramDefinition.parameterName + ".size.convert()" + separator) + paramsBuilder.append("pinned" + paramDefinition.parameterName.capitalize() + ".addressOf(0), " + paramDefinition.parameterName + ".size.convert()" + separator) } TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { - paramsBuilder.append("pinned" + paramDefinition.parameterName.capitalize() + ".addressOf(0), "+ paramDefinition.parameterName + ".size.convert()" + separator) + paramsBuilder.append("pinned" + paramDefinition.parameterName.capitalize() + ".addressOf(0), " + paramDefinition.parameterName + ".size.convert()" + separator) } TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE -> { paramsBuilder.append("pinned" + paramDefinition.parameterName.capitalize() + ".addressOf(0)" + separator) diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt index 1f64886..28a0634 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt @@ -10,21 +10,17 @@ expect class Sha512State expect class GenericHashState expect class Crypto { - fun crypto_hash_sha256_init(state: Sha256State): Int + fun crypto_hash_sha256_init(): Sha256State fun crypto_hash_sha256_update(state: Sha256State, input: UByteArray) - fun crypto_hash_sha256_final(state: Sha256State, out: UByteArray) + fun crypto_hash_sha256_final(state: Sha256State): UByteArray - fun crypto_hash_sha512_init(state: Sha512State): Int + fun crypto_hash_sha512_init(): Sha512State fun crypto_hash_sha512_update(state: Sha512State, input: UByteArray) - fun crypto_hash_sha512_final(state: Sha512State, out: UByteArray) + fun crypto_hash_sha512_final(state: Sha512State): UByteArray - fun crypto_generichash_init( - state: GenericHashState, - key: UByteArray, - outlen: Int - ): Int + fun crypto_generichash_init(key: UByteArray, outlen: Int): GenericHashState } diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt index 9b624c8..0a4c717 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt @@ -1,6 +1,7 @@ package debug.test import com.ionspin.kotlin.crypto.getSodium +import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array import kotlin.Any import kotlin.Int @@ -13,42 +14,38 @@ actual typealias Sha512State = Any actual typealias GenericHashState = Any actual class Crypto { - actual fun crypto_hash_sha256_init(state: Sha256State): Int { + actual fun crypto_hash_sha256_init(): dynamic { println("Debug") - return getSodium().crypto_hash_sha256_init(state) + return getSodium().crypto_hash_sha256_init() } actual fun crypto_hash_sha256_update(state: Sha256State, input: UByteArray) { println("Debug") - getSodium().crypto_hash_sha256_update(state, input.toUInt8Array(), input.size.toLong()) + getSodium().crypto_hash_sha256_update(state, input.toUInt8Array(), ) } - actual fun crypto_hash_sha256_final(state: Sha256State, out: UByteArray) { + actual fun crypto_hash_sha256_final(state: Sha256State): UByteArray { println("Debug") - getSodium().crypto_hash_sha256_final(state, out.toUInt8Array()) + return getSodium().crypto_hash_sha256_final(state).toUByteArray() } - actual fun crypto_hash_sha512_init(state: Sha512State): Int { + actual fun crypto_hash_sha512_init(): dynamic { println("Debug") - return getSodium().crypto_hash_sha512_init(state) + return getSodium().crypto_hash_sha512_init() } actual fun crypto_hash_sha512_update(state: Sha512State, input: UByteArray) { println("Debug") - getSodium().crypto_hash_sha512_update(state, input.toUInt8Array(), input.size.toLong()) + getSodium().crypto_hash_sha512_update(state, input.toUInt8Array(), ) } - actual fun crypto_hash_sha512_final(state: Sha512State, out: UByteArray) { + actual fun crypto_hash_sha512_final(state: Sha512State): UByteArray { println("Debug") - getSodium().crypto_hash_sha512_final(state, out.toUInt8Array()) + return getSodium().crypto_hash_sha512_final(state).toUByteArray() } - actual fun crypto_generichash_init( - state: GenericHashState, - key: UByteArray, - outlen: Int - ): Int { + actual fun crypto_generichash_init(key: UByteArray, outlen: Int): dynamic { println("Debug") - return getSodium().crypto_generichash_init(state, key.toUInt8Array(), key.size, outlen) + return getSodium().crypto_generichash_init(key.toUInt8Array(), outlen) } } diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt index 299c9a5..0acbbe5 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt @@ -15,7 +15,7 @@ actual typealias Sha512State = Hash.State512 actual typealias GenericHashState = ByteArray actual class Crypto { - actual fun crypto_hash_sha256_init(state: Sha256State): Int { + actual fun crypto_hash_sha256_init(state: Sha256State): Sha256State { println("Debug") return sodium.crypto_hash_sha256_init(state) } @@ -25,12 +25,12 @@ actual class Crypto { sodium.crypto_hash_sha256_update(state, input.asByteArray(), input.size.toLong()) } - actual fun crypto_hash_sha256_final(state: Sha256State, out: UByteArray) { + actual fun crypto_hash_sha256_final(state: Sha256State, out: UByteArray): UByteArray { println("Debug") - sodium.crypto_hash_sha256_final(state, out.asByteArray()) + return sodium.crypto_hash_sha256_final(state, out.asByteArray()) } - actual fun crypto_hash_sha512_init(state: Sha512State): Int { + actual fun crypto_hash_sha512_init(state: Sha512State): Sha512State { println("Debug") return sodium.crypto_hash_sha512_init(state) } @@ -40,16 +40,16 @@ actual class Crypto { sodium.crypto_hash_sha512_update(state, input.asByteArray(), input.size.toLong()) } - actual fun crypto_hash_sha512_final(state: Sha512State, out: UByteArray) { + actual fun crypto_hash_sha512_final(state: Sha512State, out: UByteArray): UByteArray { println("Debug") - sodium.crypto_hash_sha512_final(state, out.asByteArray()) + return sodium.crypto_hash_sha512_final(state, out.asByteArray()) } actual fun crypto_generichash_init( state: GenericHashState, key: UByteArray, outlen: Int - ): Int { + ): GenericHashState { println("Debug") return sodium.crypto_generichash_init(state, key.asByteArray(), key.size, outlen) } diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt index 37b4cc7..64285c9 100644 --- a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt @@ -1,16 +1,20 @@ package debug.test import kotlin.Byte +import kotlin.ByteArray import kotlin.Int import kotlin.UByteArray import kotlinx.cinterop.addressOf import kotlinx.cinterop.convert import kotlinx.cinterop.pin +import kotlinx.cinterop.pointed import kotlinx.cinterop.ptr +import kotlinx.cinterop.reinterpret import kotlinx.cinterop.toCValues import libsodium.crypto_generichash_blake2b_state import libsodium.crypto_hash_sha256_state import libsodium.crypto_hash_sha512_state +import libsodium.sodium_malloc actual typealias Sha256State = crypto_hash_sha256_state @@ -21,51 +25,64 @@ actual typealias GenericHashState = crypto_generichash_blake2b_state actual class Crypto { val _emitByte: Byte = 0 - val _emitByteArray: Byte = ByteArray(0) {} + val _emitByteArray: ByteArray = ByteArray(0) {} - actual fun crypto_hash_sha256_init(state: Sha256State): Int { + actual fun crypto_hash_sha256_init(): Sha256State { + val allocated = sodium_malloc(debug.test.Sha256State.size.convert())!! + val state = allocated.reinterpret().pointed println("Debug") - return libsodium.crypto_hash_sha256_init(state.ptr) + libsodium.crypto_hash_sha256_init(state.ptr) + return state } actual fun crypto_hash_sha256_update(state: Sha256State, input: UByteArray) { + println("Debug") val pinnedInput = input.pin() libsodium.crypto_hash_sha256_update(state.ptr, pinnedInput.addressOf(0), input.size.convert()) pinnedInput.unpin() } - actual fun crypto_hash_sha256_final(state: Sha256State, out: UByteArray) { + actual fun crypto_hash_sha256_final(state: Sha256State): UByteArray { + println("Debug") + val out = UByteArray(32) val pinnedOut = out.pin() libsodium.crypto_hash_sha256_final(state.ptr, pinnedOut.addressOf(0)) pinnedOut.unpin() + return out } - actual fun crypto_hash_sha512_init(state: Sha512State): Int { + actual fun crypto_hash_sha512_init(): Sha512State { + val allocated = sodium_malloc(debug.test.Sha512State.size.convert())!! + val state = allocated.reinterpret().pointed println("Debug") - return libsodium.crypto_hash_sha512_init(state.ptr) + libsodium.crypto_hash_sha512_init(state.ptr) + return state } actual fun crypto_hash_sha512_update(state: Sha512State, input: UByteArray) { + println("Debug") val pinnedInput = input.pin() libsodium.crypto_hash_sha512_update(state.ptr, pinnedInput.addressOf(0), input.size.convert()) pinnedInput.unpin() } - actual fun crypto_hash_sha512_final(state: Sha512State, out: UByteArray) { + actual fun crypto_hash_sha512_final(state: Sha512State): UByteArray { + println("Debug") + val out = UByteArray(64) val pinnedOut = out.pin() libsodium.crypto_hash_sha512_final(state.ptr, pinnedOut.addressOf(0)) pinnedOut.unpin() + return out } - actual fun crypto_generichash_init( - state: GenericHashState, - key: UByteArray, - outlen: Int - ): Int { - val pinnedKey = key.pin() + actual fun crypto_generichash_init(key: UByteArray, outlen: Int): GenericHashState { + val allocated = sodium_malloc(debug.test.GenericHashState.size.convert())!! + val state = allocated.reinterpret().pointed println("Debug") - return libsodium.crypto_generichash_init(state.ptr, pinnedKey.addressOf(0), key.size.convert(), + val pinnedKey = key.pin() + libsodium.crypto_generichash_init(state.ptr, pinnedKey.addressOf(0), key.size.convert(), outlen.convert()) pinnedKey.unpin() + return state } }