diff --git a/crypto-ffi/bindings/android/src/main/kotlin/.gitkeep b/crypto-ffi/bindings/android/src/main/kotlin/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/CoreCrypto.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/CoreCrypto.kt new file mode 100644 index 0000000000..ce863b0844 --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/CoreCrypto.kt @@ -0,0 +1,6886 @@ +// This file was autogenerated by some hot garbage in the `uniffi` crate. +// Trust me, you don't want to mess with it! + +@file:Suppress("NAME_SHADOWING") + +package com.wire.crypto; + +// Common helper code. +// +// Ideally this would live in a separate .kt file where it can be unittested etc +// in isolation, and perhaps even published as a re-useable package. +// +// However, it's important that the detils of how this helper code works (e.g. the +// way that different builtin types are passed across the FFI) exactly match what's +// expected by the Rust code on the other side of the interface. In practice right +// now that means coming from the exact some version of `uniffi` that was used to +// compile the Rust component. The easiest way to ensure this is to bundle the Kotlin +// helpers directly inline like we're doing here. + +import com.sun.jna.Library +import com.sun.jna.IntegerType +import com.sun.jna.Native +import com.sun.jna.Pointer +import com.sun.jna.Structure +import com.sun.jna.Callback +import com.sun.jna.ptr.* +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicLong +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +// This is a helper for safely working with byte buffers returned from the Rust code. +// A rust-owned buffer is represented by its capacity, its current length, and a +// pointer to the underlying data. + +@Structure.FieldOrder("capacity", "len", "data") +open class RustBuffer : Structure() { + @JvmField var capacity: Int = 0 + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue: RustBuffer(), Structure.ByValue + class ByReference: RustBuffer(), Structure.ByReference + + companion object { + internal fun alloc(size: Int = 0) = rustCall() { status -> + _UniFFILib.INSTANCE.ffi_CoreCrypto_rustbuffer_alloc(size, status).also { + if(it.data == null) { + throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") + } + } + } + + internal fun free(buf: RustBuffer.ByValue) = rustCall() { status -> + _UniFFILib.INSTANCE.ffi_CoreCrypto_rustbuffer_free(buf, status) + } + } + + @Suppress("TooGenericExceptionThrown") + fun asByteBuffer() = + this.data?.getByteBuffer(0, this.len.toLong())?.also { + it.order(ByteOrder.BIG_ENDIAN) + } +} + +/** + * The equivalent of the `*mut RustBuffer` type. + * Required for callbacks taking in an out pointer. + * + * Size is the sum of all values in the struct. + */ +class RustBufferByReference : ByReference(16) { + /** + * Set the pointed-to `RustBuffer` to the given value. + */ + fun setValue(value: RustBuffer.ByValue) { + // NOTE: The offsets are as they are in the C-like struct. + val pointer = getPointer() + pointer.setInt(0, value.capacity) + pointer.setInt(4, value.len) + pointer.setPointer(8, value.data) + } + + /** + * Get a `RustBuffer.ByValue` from this reference. + */ + fun getValue(): RustBuffer.ByValue { + val pointer = getPointer() + val value = RustBuffer.ByValue() + value.writeField("capacity", pointer.getInt(0)) + value.writeField("len", pointer.getInt(4)) + value.writeField("data", pointer.getPointer(8)) + + return value + } +} + +// This is a helper for safely passing byte references into the rust code. +// It's not actually used at the moment, because there aren't many things that you +// can take a direct pointer to in the JVM, and if we're going to copy something +// then we might as well copy it into a `RustBuffer`. But it's here for API +// completeness. + +@Structure.FieldOrder("len", "data") +open class ForeignBytes : Structure() { + @JvmField var len: Int = 0 + @JvmField var data: Pointer? = null + + class ByValue : ForeignBytes(), Structure.ByValue +} +// The FfiConverter interface handles converter types to and from the FFI +// +// All implementing objects should be public to support external types. When a +// type is external we need to import it's FfiConverter. +public interface FfiConverter { + // Convert an FFI type to a Kotlin type + fun lift(value: FfiType): KotlinType + + // Convert an Kotlin type to an FFI type + fun lower(value: KotlinType): FfiType + + // Read a Kotlin type from a `ByteBuffer` + fun read(buf: ByteBuffer): KotlinType + + // Calculate bytes to allocate when creating a `RustBuffer` + // + // This must return at least as many bytes as the write() function will + // write. It can return more bytes than needed, for example when writing + // Strings we can't know the exact bytes needed until we the UTF-8 + // encoding, so we pessimistically allocate the largest size possible (3 + // bytes per codepoint). Allocating extra bytes is not really a big deal + // because the `RustBuffer` is short-lived. + fun allocationSize(value: KotlinType): Int + + // Write a Kotlin type to a `ByteBuffer` + fun write(value: KotlinType, buf: ByteBuffer) + + // Lower a value into a `RustBuffer` + // + // This method lowers a value into a `RustBuffer` rather than the normal + // FfiType. It's used by the callback interface code. Callback interface + // returns are always serialized into a `RustBuffer` regardless of their + // normal FFI type. + fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { + val rbuf = RustBuffer.alloc(allocationSize(value)) + try { + val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + write(value, bbuf) + rbuf.writeField("len", bbuf.position()) + return rbuf + } catch (e: Throwable) { + RustBuffer.free(rbuf) + throw e + } + } + + // Lift a value from a `RustBuffer`. + // + // This here mostly because of the symmetry with `lowerIntoRustBuffer()`. + // It's currently only used by the `FfiConverterRustBuffer` class below. + fun liftFromRustBuffer(rbuf: RustBuffer.ByValue): KotlinType { + val byteBuf = rbuf.asByteBuffer()!! + try { + val item = read(byteBuf) + if (byteBuf.hasRemaining()) { + throw RuntimeException("junk remaining in buffer after lifting, something is very wrong!!") + } + return item + } finally { + RustBuffer.free(rbuf) + } + } +} + +// FfiConverter that uses `RustBuffer` as the FfiType +public interface FfiConverterRustBuffer: FfiConverter { + override fun lift(value: RustBuffer.ByValue) = liftFromRustBuffer(value) + override fun lower(value: KotlinType) = lowerIntoRustBuffer(value) +} +// A handful of classes and functions to support the generated data structures. +// This would be a good candidate for isolating in its own ffi-support lib. +// Error runtime. +@Structure.FieldOrder("code", "error_buf") +internal open class RustCallStatus : Structure() { + @JvmField var code: Byte = 0 + @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() + + class ByValue: RustCallStatus(), Structure.ByValue + + fun isSuccess(): Boolean { + return code == 0.toByte() + } + + fun isError(): Boolean { + return code == 1.toByte() + } + + fun isPanic(): Boolean { + return code == 2.toByte() + } +} + +class InternalException(message: String) : Exception(message) + +// Each top-level error class has a companion object that can lift the error from the call status's rust buffer +interface CallStatusErrorHandler { + fun lift(error_buf: RustBuffer.ByValue): E; +} + +// Helpers for calling Rust +// In practice we usually need to be synchronized to call this safely, so it doesn't +// synchronize itself + +// Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err +private inline fun rustCallWithError(errorHandler: CallStatusErrorHandler, callback: (RustCallStatus) -> U): U { + var status = RustCallStatus(); + val return_value = callback(status) + checkCallStatus(errorHandler, status) + return return_value +} + +// Check RustCallStatus and throw an error if the call wasn't successful +private fun checkCallStatus(errorHandler: CallStatusErrorHandler, status: RustCallStatus) { + if (status.isSuccess()) { + return + } else if (status.isError()) { + throw errorHandler.lift(status.error_buf) + } else if (status.isPanic()) { + // when the rust code sees a panic, it tries to construct a rustbuffer + // with the message. but if that code panics, then it just sends back + // an empty buffer. + if (status.error_buf.len > 0) { + throw InternalException(FfiConverterString.lift(status.error_buf)) + } else { + throw InternalException("Rust panic") + } + } else { + throw InternalException("Unknown rust call status: $status.code") + } +} + +// CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object NullCallStatusErrorHandler: CallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): InternalException { + RustBuffer.free(error_buf) + return InternalException("Unexpected CALL_ERROR") + } +} + +// Call a rust function that returns a plain value +private inline fun rustCall(callback: (RustCallStatus) -> U): U { + return rustCallWithError(NullCallStatusErrorHandler, callback); +} + +// IntegerType that matches Rust's `usize` / C's `size_t` +public class USize(value: Long = 0) : IntegerType(Native.SIZE_T_SIZE, value, true) { + // This is needed to fill in the gaps of IntegerType's implementation of Number for Kotlin. + override fun toByte() = toInt().toByte() + override fun toChar() = toInt().toChar() + override fun toShort() = toInt().toShort() + + fun writeToBuffer(buf: ByteBuffer) { + // Make sure we always write usize integers using native byte-order, since they may be + // casted to pointer values + buf.order(ByteOrder.nativeOrder()) + try { + when (Native.SIZE_T_SIZE) { + 4 -> buf.putInt(toInt()) + 8 -> buf.putLong(toLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } + } + + companion object { + val size: Int + get() = Native.SIZE_T_SIZE + + fun readFromBuffer(buf: ByteBuffer) : USize { + // Make sure we always read usize integers using native byte-order, since they may be + // casted from pointer values + buf.order(ByteOrder.nativeOrder()) + try { + return when (Native.SIZE_T_SIZE) { + 4 -> USize(buf.getInt().toLong()) + 8 -> USize(buf.getLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } + } + } +} + + +// Map handles to objects +// +// This is used when the Rust code expects an opaque pointer to represent some foreign object. +// Normally we would pass a pointer to the object, but JNA doesn't support getting a pointer from an +// object reference , nor does it support leaking a reference to Rust. +// +// Instead, this class maps USize values to objects so that we can pass a pointer-sized type to +// Rust when it needs an opaque pointer. +// +// TODO: refactor callbacks to use this class +internal class UniFfiHandleMap { + private val map = ConcurrentHashMap() + // Use AtomicInteger for our counter, since we may be on a 32-bit system. 4 billion possible + // values seems like enough. If somehow we generate 4 billion handles, then this will wrap + // around back to zero and we can assume the first handle generated will have been dropped by + // then. + private val counter = java.util.concurrent.atomic.AtomicInteger(0) + + val size: Int + get() = map.size + + fun insert(obj: T): USize { + val handle = USize(counter.getAndAdd(1).toLong()) + map.put(handle, obj) + return handle + } + + fun get(handle: USize): T? { + return map.get(handle) + } + + fun remove(handle: USize) { + map.remove(handle) + } +} + +// Contains loading, initialization code, +// and the FFI Function declarations in a com.sun.jna.Library. +@Synchronized +private fun findLibraryName(componentName: String): String { + val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") + if (libOverride != null) { + return libOverride + } + return "core_crypto_ffi" +} + +private inline fun loadIndirect( + componentName: String +): Lib { + return Native.load(findLibraryName(componentName), Lib::class.java) +} + +// A JNA Library to expose the extern-C FFI definitions. +// This is an implementation detail which will be called internally by the public API. + +internal interface _UniFFILib : Library { + companion object { + internal val INSTANCE: _UniFFILib by lazy { + loadIndirect<_UniFFILib>(componentName = "CoreCrypto") + .also { lib: _UniFFILib -> + uniffiCheckContractApiVersion(lib) + uniffiCheckApiChecksums(lib) + FfiConverterForeignExecutor.register(lib) + FfiConverterTypeCoreCryptoCallbacks.register(lib) + } + } + } + + fun uniffi_core_crypto_ffi_fn_free_corecrypto(`ptr`: Pointer,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_add_clients_to_conversation(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`clients`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_clear_pending_commit(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_clear_pending_group_from_external_commit(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_clear_pending_proposal(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`proposalRef`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_client_keypackages(`ptr`: Pointer,`ciphersuite`: Short,`credentialType`: RustBuffer.ByValue,`amountRequested`: Int,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_client_public_key(`ptr`: Pointer,`ciphersuite`: Short,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_client_valid_keypackages_count(`ptr`: Pointer,`ciphersuite`: Short,`credentialType`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackLong,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_commit_accepted(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_commit_pending_proposals(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_conversation_epoch(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackLong,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_conversation_exists(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_create_conversation(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`creatorCredentialType`: RustBuffer.ByValue,`config`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_decrypt_message(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`payload`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_delete_keypackages(`ptr`: Pointer,`refs`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_conversation_state(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_enrollment_stash(`ptr`: Pointer,`enrollment`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_enrollment_stash_pop(`ptr`: Pointer,`handle`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackPointer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_is_enabled(`ptr`: Pointer,`ciphersuite`: Short,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_mls_init_only(`ptr`: Pointer,`enrollment`: Pointer,`certificateChain`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_new_activation_enrollment(`ptr`: Pointer,`clientId`: RustBuffer.ByValue,`displayName`: RustBuffer.ByValue,`handle`: RustBuffer.ByValue,`expiryDays`: Int,`ciphersuite`: Short,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackPointer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_new_enrollment(`ptr`: Pointer,`clientId`: RustBuffer.ByValue,`displayName`: RustBuffer.ByValue,`handle`: RustBuffer.ByValue,`expiryDays`: Int,`ciphersuite`: Short,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackPointer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_new_rotate_enrollment(`ptr`: Pointer,`clientId`: RustBuffer.ByValue,`displayName`: RustBuffer.ByValue,`handle`: RustBuffer.ByValue,`expiryDays`: Int,`ciphersuite`: Short,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackPointer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_rotate_all(`ptr`: Pointer,`enrollment`: Pointer,`certificateChain`: RustBuffer.ByValue,`newKeyPackagesCount`: Int,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_encrypt_message(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`message`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_export_secret_key(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`keyLength`: Int,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_get_client_ids(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_join_by_external_commit(`ptr`: Pointer,`groupInfo`: RustBuffer.ByValue,`customConfiguration`: RustBuffer.ByValue,`credentialType`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_mark_conversation_as_child_of(`ptr`: Pointer,`childId`: RustBuffer.ByValue,`parentId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_merge_pending_group_from_external_commit(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_mls_generate_keypairs(`ptr`: Pointer,`ciphersuites`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_mls_init(`ptr`: Pointer,`clientId`: RustBuffer.ByValue,`ciphersuites`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_mls_init_with_client_id(`ptr`: Pointer,`clientId`: RustBuffer.ByValue,`tmpClientIds`: RustBuffer.ByValue,`ciphersuites`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_new_add_proposal(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`keypackage`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_new_external_add_proposal(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`epoch`: Long,`ciphersuite`: Short,`credentialType`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_new_remove_proposal(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`clientId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_new_update_proposal(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_process_welcome_message(`ptr`: Pointer,`welcomeMessage`: RustBuffer.ByValue,`customConfiguration`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_cryptobox_migrate(`ptr`: Pointer,`path`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_decrypt(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`ciphertext`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_encrypt(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`plaintext`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_encrypt_batched(`ptr`: Pointer,`sessions`: RustBuffer.ByValue,`plaintext`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint_local(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint_prekeybundle(`ptr`: Pointer,`prekey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus, + ): RustBuffer.ByValue + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint_remote(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_init(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_last_error_code(`ptr`: Pointer,_uniffi_out_err: RustCallStatus, + ): Int + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_last_resort_prekey(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_last_resort_prekey_id(`ptr`: Pointer,_uniffi_out_err: RustCallStatus, + ): Short + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_new_prekey(`ptr`: Pointer,`prekeyId`: Short,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_new_prekey_auto(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_delete(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_exists(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_from_message(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`envelope`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_from_prekey(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`prekey`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_save(`ptr`: Pointer,`sessionId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_random_bytes(`ptr`: Pointer,`len`: Int,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_remove_clients_from_conversation(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`clients`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_reseed_rng(`ptr`: Pointer,`seed`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_restore_from_disk(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_set_callbacks(`ptr`: Pointer,`callbacks`: Long,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_unload(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_update_keying_material(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_update_trust_anchors_from_conversation(`ptr`: Pointer,`id`: RustBuffer.ByValue,`removeDomainNames`: RustBuffer.ByValue,`addTrustAnchors`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_wipe(`ptr`: Pointer,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_corecrypto_wipe_conversation(`ptr`: Pointer,`conversationId`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_free_wiree2eidentity(`ptr`: Pointer,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_certificate_request(`ptr`: Pointer,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_check_order_request(`ptr`: Pointer,`orderUrl`: RustBuffer.ByValue,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_check_order_response(`ptr`: Pointer,`order`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_create_dpop_token(`ptr`: Pointer,`expirySecs`: Int,`backendNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_directory_response(`ptr`: Pointer,`directory`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_finalize_request(`ptr`: Pointer,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_finalize_response(`ptr`: Pointer,`finalize`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_account_request(`ptr`: Pointer,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_account_response(`ptr`: Pointer,`account`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_authz_request(`ptr`: Pointer,`url`: RustBuffer.ByValue,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_authz_response(`ptr`: Pointer,`authz`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_challenge_response(`ptr`: Pointer,`challenge`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackByte,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_dpop_challenge_request(`ptr`: Pointer,`accessToken`: RustBuffer.ByValue,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_oidc_challenge_request(`ptr`: Pointer,`idToken`: RustBuffer.ByValue,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_order_request(`ptr`: Pointer,`previousNonce`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_order_response(`ptr`: Pointer,`order`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackRustBuffer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_CoreCrypto_fn_init_callback_corecryptocallbacks(`callbackStub`: ForeignCallback,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_CoreCrypto_fn_func_version(_uniffi_out_err: RustCallStatus, + ): RustBuffer.ByValue + fun uniffi_core_crypto_ffi_fn_func_core_crypto_deferred_init(`path`: RustBuffer.ByValue,`key`: RustBuffer.ByValue,`ciphersuites`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackPointer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun uniffi_core_crypto_ffi_fn_func_core_crypto_new(`path`: RustBuffer.ByValue,`key`: RustBuffer.ByValue,`clientId`: RustBuffer.ByValue,`ciphersuites`: RustBuffer.ByValue,`uniffiExecutor`: USize,`uniffiCallback`: UniFfiFutureCallbackPointer,`uniffiCallbackData`: USize,_uniffi_out_err: RustCallStatus, + ): Unit + fun ffi_CoreCrypto_rustbuffer_alloc(`size`: Int,_uniffi_out_err: RustCallStatus, + ): RustBuffer.ByValue + fun ffi_CoreCrypto_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,_uniffi_out_err: RustCallStatus, + ): RustBuffer.ByValue + fun ffi_CoreCrypto_rustbuffer_free(`buf`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus, + ): Unit + fun ffi_CoreCrypto_rustbuffer_reserve(`buf`: RustBuffer.ByValue,`additional`: Int,_uniffi_out_err: RustCallStatus, + ): RustBuffer.ByValue + fun uniffi_CoreCrypto_checksum_func_version( + ): Short + fun uniffi_core_crypto_ffi_checksum_func_core_crypto_deferred_init( + ): Short + fun uniffi_core_crypto_ffi_checksum_func_core_crypto_new( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_add_clients_to_conversation( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_clear_pending_commit( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_clear_pending_group_from_external_commit( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_clear_pending_proposal( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_client_keypackages( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_client_public_key( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_client_valid_keypackages_count( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_commit_accepted( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_commit_pending_proposals( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_conversation_epoch( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_conversation_exists( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_create_conversation( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_decrypt_message( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_delete_keypackages( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_conversation_state( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_enrollment_stash( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_enrollment_stash_pop( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_is_enabled( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_mls_init_only( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_new_activation_enrollment( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_new_enrollment( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_new_rotate_enrollment( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_rotate_all( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_encrypt_message( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_export_secret_key( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_get_client_ids( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_join_by_external_commit( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_mark_conversation_as_child_of( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_merge_pending_group_from_external_commit( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_mls_generate_keypairs( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_mls_init( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_mls_init_with_client_id( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_new_add_proposal( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_new_external_add_proposal( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_new_remove_proposal( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_new_update_proposal( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_process_welcome_message( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_cryptobox_migrate( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_decrypt( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_encrypt( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_encrypt_batched( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint_local( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint_prekeybundle( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint_remote( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_init( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_last_error_code( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_last_resort_prekey( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_last_resort_prekey_id( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_new_prekey( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_new_prekey_auto( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_delete( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_exists( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_from_message( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_from_prekey( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_save( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_random_bytes( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_remove_clients_from_conversation( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_reseed_rng( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_restore_from_disk( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_set_callbacks( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_unload( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_update_keying_material( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_update_trust_anchors_from_conversation( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_wipe( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_corecrypto_wipe_conversation( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_certificate_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_check_order_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_check_order_response( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_create_dpop_token( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_directory_response( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_finalize_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_finalize_response( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_account_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_account_response( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_authz_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_authz_response( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_challenge_response( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_dpop_challenge_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_oidc_challenge_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_order_request( + ): Short + fun uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_order_response( + ): Short + fun uniffi_foreign_executor_callback_set(`callback`: UniFfiForeignExecutorCallback, + ): Unit + fun ffi_CoreCrypto_uniffi_contract_version( + ): Int + +} + +private fun uniffiCheckContractApiVersion(lib: _UniFFILib) { + // Get the bindings contract version from our ComponentInterface + val bindings_contract_version = 22 + // Get the scaffolding contract version by calling the into the dylib + val scaffolding_contract_version = lib.ffi_CoreCrypto_uniffi_contract_version() + if (bindings_contract_version != scaffolding_contract_version) { + throw RuntimeException("UniFFI contract version mismatch: try cleaning and rebuilding your project") + } +} + +@Suppress("UNUSED_PARAMETER") +private fun uniffiCheckApiChecksums(lib: _UniFFILib) { + if (lib.uniffi_CoreCrypto_checksum_func_version() != 45572.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_func_core_crypto_deferred_init() != 50792.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_func_core_crypto_new() != 62176.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_add_clients_to_conversation() != 62511.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_clear_pending_commit() != 9629.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_clear_pending_group_from_external_commit() != 9271.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_clear_pending_proposal() != 43997.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_client_keypackages() != 22726.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_client_public_key() != 27713.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_client_valid_keypackages_count() != 46072.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_commit_accepted() != 8390.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_commit_pending_proposals() != 16509.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_conversation_epoch() != 28765.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_conversation_exists() != 6810.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_create_conversation() != 28082.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_decrypt_message() != 65249.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_delete_keypackages() != 58695.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_conversation_state() != 42555.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_enrollment_stash() != 58951.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_enrollment_stash_pop() != 3056.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_is_enabled() != 16968.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_mls_init_only() != 39276.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_new_activation_enrollment() != 40456.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_new_enrollment() != 37974.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_new_rotate_enrollment() != 50952.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_e2ei_rotate_all() != 47334.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_encrypt_message() != 53093.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_export_secret_key() != 61849.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_get_client_ids() != 12379.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_join_by_external_commit() != 31602.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_mark_conversation_as_child_of() != 56243.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_merge_pending_group_from_external_commit() != 3670.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_mls_generate_keypairs() != 64135.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_mls_init() != 51669.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_mls_init_with_client_id() != 63005.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_new_add_proposal() != 64278.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_new_external_add_proposal() != 32412.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_new_remove_proposal() != 20291.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_new_update_proposal() != 19146.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_process_welcome_message() != 15102.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_cryptobox_migrate() != 64063.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_decrypt() != 34647.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_encrypt() != 37019.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_encrypt_batched() != 24794.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint() != 51991.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint_local() != 34081.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint_prekeybundle() != 34156.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_fingerprint_remote() != 62837.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_init() != 29455.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_last_error_code() != 51242.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_last_resort_prekey() != 64472.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_last_resort_prekey_id() != 24224.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_new_prekey() != 48609.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_new_prekey_auto() != 41516.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_delete() != 30186.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_exists() != 10028.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_from_message() != 31526.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_from_prekey() != 64902.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_proteus_session_save() != 14424.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_random_bytes() != 43930.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_remove_clients_from_conversation() != 61795.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_reseed_rng() != 65271.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_restore_from_disk() != 37057.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_set_callbacks() != 39368.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_unload() != 2006.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_update_keying_material() != 10667.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_update_trust_anchors_from_conversation() != 24059.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_wipe() != 57687.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_corecrypto_wipe_conversation() != 45386.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_certificate_request() != 49443.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_check_order_request() != 16667.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_check_order_response() != 32230.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_create_dpop_token() != 18677.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_directory_response() != 54824.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_finalize_request() != 30897.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_finalize_response() != 22569.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_account_request() != 18717.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_account_response() != 15851.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_authz_request() != 52568.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_authz_response() != 47168.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_challenge_response() != 33196.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_dpop_challenge_request() != 35143.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_oidc_challenge_request() != 9125.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_order_request() != 17643.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_core_crypto_ffi_checksum_method_wiree2eidentity_new_order_response() != 35935.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } +} + +// Public interface members begin here. + + +public object FfiConverterUByte: FfiConverter { + override fun lift(value: Byte): UByte { + return value.toUByte() + } + + override fun read(buf: ByteBuffer): UByte { + return lift(buf.get()) + } + + override fun lower(value: UByte): Byte { + return value.toByte() + } + + override fun allocationSize(value: UByte) = 1 + + override fun write(value: UByte, buf: ByteBuffer) { + buf.put(value.toByte()) + } +} + +public object FfiConverterUShort: FfiConverter { + override fun lift(value: Short): UShort { + return value.toUShort() + } + + override fun read(buf: ByteBuffer): UShort { + return lift(buf.getShort()) + } + + override fun lower(value: UShort): Short { + return value.toShort() + } + + override fun allocationSize(value: UShort) = 2 + + override fun write(value: UShort, buf: ByteBuffer) { + buf.putShort(value.toShort()) + } +} + +public object FfiConverterUInt: FfiConverter { + override fun lift(value: Int): UInt { + return value.toUInt() + } + + override fun read(buf: ByteBuffer): UInt { + return lift(buf.getInt()) + } + + override fun lower(value: UInt): Int { + return value.toInt() + } + + override fun allocationSize(value: UInt) = 4 + + override fun write(value: UInt, buf: ByteBuffer) { + buf.putInt(value.toInt()) + } +} + +public object FfiConverterULong: FfiConverter { + override fun lift(value: Long): ULong { + return value.toULong() + } + + override fun read(buf: ByteBuffer): ULong { + return lift(buf.getLong()) + } + + override fun lower(value: ULong): Long { + return value.toLong() + } + + override fun allocationSize(value: ULong) = 8 + + override fun write(value: ULong, buf: ByteBuffer) { + buf.putLong(value.toLong()) + } +} + +public object FfiConverterBoolean: FfiConverter { + override fun lift(value: Byte): Boolean { + return value.toInt() != 0 + } + + override fun read(buf: ByteBuffer): Boolean { + return lift(buf.get()) + } + + override fun lower(value: Boolean): Byte { + return if (value) 1.toByte() else 0.toByte() + } + + override fun allocationSize(value: Boolean) = 1 + + override fun write(value: Boolean, buf: ByteBuffer) { + buf.put(lower(value)) + } +} + +public object FfiConverterString: FfiConverter { + // Note: we don't inherit from FfiConverterRustBuffer, because we use a + // special encoding when lowering/lifting. We can use `RustBuffer.len` to + // store our length and avoid writing it out to the buffer. + override fun lift(value: RustBuffer.ByValue): String { + try { + val byteArr = ByteArray(value.len) + value.asByteBuffer()!!.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } finally { + RustBuffer.free(value) + } + } + + override fun read(buf: ByteBuffer): String { + val len = buf.getInt() + val byteArr = ByteArray(len) + buf.get(byteArr) + return byteArr.toString(Charsets.UTF_8) + } + + override fun lower(value: String): RustBuffer.ByValue { + val byteArr = value.toByteArray(Charsets.UTF_8) + // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us + // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. + val rbuf = RustBuffer.alloc(byteArr.size) + rbuf.asByteBuffer()!!.put(byteArr) + return rbuf + } + + // We aren't sure exactly how many bytes our string will be once it's UTF-8 + // encoded. Allocate 3 bytes per unicode codepoint which will always be + // enough. + override fun allocationSize(value: String): Int { + val sizeForLength = 4 + val sizeForString = value.length * 3 + return sizeForLength + sizeForString + } + + override fun write(value: String, buf: ByteBuffer) { + val byteArr = value.toByteArray(Charsets.UTF_8) + buf.putInt(byteArr.size) + buf.put(byteArr) + } +} + +public object FfiConverterByteArray: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ByteArray { + val len = buf.getInt() + val byteArr = ByteArray(len) + buf.get(byteArr) + return byteArr + } + override fun allocationSize(value: ByteArray): Int { + return 4 + value.size + } + override fun write(value: ByteArray, buf: ByteBuffer) { + buf.putInt(value.size) + buf.put(value) + } +} + + +public object FfiConverterDuration: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): java.time.Duration { + // Type mismatch (should be u64) but we check for overflow/underflow below + val seconds = buf.getLong() + // Type mismatch (should be u32) but we check for overflow/underflow below + val nanoseconds = buf.getInt().toLong() + if (seconds < 0) { + throw java.time.DateTimeException("Duration exceeds minimum or maximum value supported by uniffi") + } + if (nanoseconds < 0) { + throw java.time.DateTimeException("Duration nanoseconds exceed minimum or maximum supported by uniffi") + } + return java.time.Duration.ofSeconds(seconds, nanoseconds) + } + + // 8 bytes for seconds, 4 bytes for nanoseconds + override fun allocationSize(value: java.time.Duration) = 12 + + override fun write(value: java.time.Duration, buf: ByteBuffer) { + if (value.seconds < 0) { + // Rust does not support negative Durations + throw IllegalArgumentException("Invalid duration, must be non-negative") + } + + if (value.nano < 0) { + // Java docs provide guarantee that nano will always be positive, so this should be impossible + // See: https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html + throw IllegalArgumentException("Invalid duration, nano value must be non-negative") + } + + // Type mismatch (should be u64) but since Rust doesn't support negative durations we should be OK + buf.putLong(value.seconds) + // Type mismatch (should be u32) but since values will always be between 0 and 999,999,999 it should be OK + buf.putInt(value.nano) + } +} + + +// Interface implemented by anything that can contain an object reference. +// +// Such types expose a `destroy()` method that must be called to cleanly +// dispose of the contained objects. Failure to call this method may result +// in memory leaks. +// +// The easiest way to ensure this method is called is to use the `.use` +// helper method to execute a block and destroy the object at the end. +interface Disposable { + fun destroy() + companion object { + fun destroy(vararg args: Any?) { + args.filterIsInstance() + .forEach(Disposable::destroy) + } + } +} + +inline fun T.use(block: (T) -> R) = + try { + block(this) + } finally { + try { + // N.B. our implementation is on the nullable type `Disposable?`. + this?.destroy() + } catch (e: Throwable) { + // swallow + } + } + +// The base class for all UniFFI Object types. +// +// This class provides core operations for working with the Rust `Arc` pointer to +// the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// the Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each `FFIObject` instance holds an opaque pointer to the underlying Rust struct. +// Method calls need to read this pointer from the object's state and pass it in to +// the Rust FFI. +// +// * When an `FFIObject` is no longer needed, its pointer should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an `FFIObject` instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so will +// leak the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// If we try to implement this with mutual exclusion on access to the pointer, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the pointer, but is interrupted +// before it can pass the pointer over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read pointer value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each `FFIObject` an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// In the future we may be able to replace some of this with automatic finalization logic, such as using +// the new "Cleaner" functionaility in Java 9. The above scheme has been designed to work even if `destroy` is +// invoked by garbage-collection machinery rather than by calling code (which by the way, it's apparently also +// possible for the JVM to finalize an object while there is an in-flight call to one of its methods [1], +// so there would still be some complexity here). +// +// Sigh...all of this for want of a robust finalization mechanism. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// +abstract class FFIObject( + protected val pointer: Pointer +): Disposable, AutoCloseable { + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + open protected fun freeRustArcPtr() { + // To be overridden in subclasses. + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + this.freeRustArcPtr() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.pointer) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + this.freeRustArcPtr() + } + } + } +} + +public interface CoreCryptoInterface { + @Throws(CryptoException::class) + suspend fun `addClientsToConversation`(`conversationId`: List, `clients`: List): MemberAddedMessages@Throws(CryptoException::class) + suspend fun `clearPendingCommit`(`conversationId`: List)@Throws(CryptoException::class) + suspend fun `clearPendingGroupFromExternalCommit`(`conversationId`: List)@Throws(CryptoException::class) + suspend fun `clearPendingProposal`(`conversationId`: List, `proposalRef`: List)@Throws(CryptoException::class) + suspend fun `clientKeypackages`(`ciphersuite`: Ciphersuite, `credentialType`: MlsCredentialType, `amountRequested`: UInt): List>@Throws(CryptoException::class) + suspend fun `clientPublicKey`(`ciphersuite`: Ciphersuite): List@Throws(CryptoException::class) + suspend fun `clientValidKeypackagesCount`(`ciphersuite`: Ciphersuite, `credentialType`: MlsCredentialType): ULong@Throws(CryptoException::class) + suspend fun `commitAccepted`(`conversationId`: List)@Throws(CryptoException::class) + suspend fun `commitPendingProposals`(`conversationId`: List): CommitBundle?@Throws(CryptoException::class) + suspend fun `conversationEpoch`(`conversationId`: List): ULong + suspend fun `conversationExists`(`conversationId`: List): Boolean@Throws(CryptoException::class) + suspend fun `createConversation`(`conversationId`: List, `creatorCredentialType`: MlsCredentialType, `config`: ConversationConfiguration)@Throws(CryptoException::class) + suspend fun `decryptMessage`(`conversationId`: List, `payload`: List): DecryptedMessage@Throws(CryptoException::class) + suspend fun `deleteKeypackages`(`refs`: List>)@Throws(CryptoException::class) + suspend fun `e2eiConversationState`(`conversationId`: List): E2eiConversationState@Throws(CryptoException::class) + suspend fun `e2eiEnrollmentStash`(`enrollment`: WireE2eIdentity): List@Throws(CryptoException::class) + suspend fun `e2eiEnrollmentStashPop`(`handle`: List): WireE2eIdentity@Throws(CryptoException::class) + suspend fun `e2eiIsEnabled`(`ciphersuite`: Ciphersuite): Boolean@Throws(CryptoException::class) + suspend fun `e2eiMlsInitOnly`(`enrollment`: WireE2eIdentity, `certificateChain`: String)@Throws(CryptoException::class) + suspend fun `e2eiNewActivationEnrollment`(`clientId`: String, `displayName`: String, `handle`: String, `expiryDays`: UInt, `ciphersuite`: Ciphersuite): WireE2eIdentity@Throws(CryptoException::class) + suspend fun `e2eiNewEnrollment`(`clientId`: String, `displayName`: String, `handle`: String, `expiryDays`: UInt, `ciphersuite`: Ciphersuite): WireE2eIdentity@Throws(CryptoException::class) + suspend fun `e2eiNewRotateEnrollment`(`clientId`: String, `displayName`: String?, `handle`: String?, `expiryDays`: UInt, `ciphersuite`: Ciphersuite): WireE2eIdentity@Throws(CryptoException::class) + suspend fun `e2eiRotateAll`(`enrollment`: WireE2eIdentity, `certificateChain`: String, `newKeyPackagesCount`: UInt): RotateBundle@Throws(CryptoException::class) + suspend fun `encryptMessage`(`conversationId`: List, `message`: List): List@Throws(CryptoException::class) + suspend fun `exportSecretKey`(`conversationId`: List, `keyLength`: UInt): List@Throws(CryptoException::class) + suspend fun `getClientIds`(`conversationId`: List): List@Throws(CryptoException::class) + suspend fun `joinByExternalCommit`(`groupInfo`: List, `customConfiguration`: CustomConfiguration, `credentialType`: MlsCredentialType): ConversationInitBundle@Throws(CryptoException::class) + suspend fun `markConversationAsChildOf`(`childId`: List, `parentId`: List)@Throws(CryptoException::class) + suspend fun `mergePendingGroupFromExternalCommit`(`conversationId`: List): List?@Throws(CryptoException::class) + suspend fun `mlsGenerateKeypairs`(`ciphersuites`: Ciphersuites): List@Throws(CryptoException::class) + suspend fun `mlsInit`(`clientId`: ClientId, `ciphersuites`: Ciphersuites)@Throws(CryptoException::class) + suspend fun `mlsInitWithClientId`(`clientId`: ClientId, `tmpClientIds`: List, `ciphersuites`: Ciphersuites)@Throws(CryptoException::class) + suspend fun `newAddProposal`(`conversationId`: List, `keypackage`: List): ProposalBundle@Throws(CryptoException::class) + suspend fun `newExternalAddProposal`(`conversationId`: List, `epoch`: ULong, `ciphersuite`: Ciphersuite, `credentialType`: MlsCredentialType): List@Throws(CryptoException::class) + suspend fun `newRemoveProposal`(`conversationId`: List, `clientId`: ClientId): ProposalBundle@Throws(CryptoException::class) + suspend fun `newUpdateProposal`(`conversationId`: List): ProposalBundle@Throws(CryptoException::class) + suspend fun `processWelcomeMessage`(`welcomeMessage`: List, `customConfiguration`: CustomConfiguration): List@Throws(CryptoException::class) + suspend fun `proteusCryptoboxMigrate`(`path`: String)@Throws(CryptoException::class) + suspend fun `proteusDecrypt`(`sessionId`: String, `ciphertext`: List): List@Throws(CryptoException::class) + suspend fun `proteusEncrypt`(`sessionId`: String, `plaintext`: List): List@Throws(CryptoException::class) + suspend fun `proteusEncryptBatched`(`sessions`: List, `plaintext`: List): Map>@Throws(CryptoException::class) + suspend fun `proteusFingerprint`(): String@Throws(CryptoException::class) + suspend fun `proteusFingerprintLocal`(`sessionId`: String): String@Throws(CryptoException::class) + fun `proteusFingerprintPrekeybundle`(`prekey`: List): String@Throws(CryptoException::class) + suspend fun `proteusFingerprintRemote`(`sessionId`: String): String@Throws(CryptoException::class) + suspend fun `proteusInit`() + fun `proteusLastErrorCode`(): UInt@Throws(CryptoException::class) + suspend fun `proteusLastResortPrekey`(): List@Throws(CryptoException::class) + fun `proteusLastResortPrekeyId`(): UShort@Throws(CryptoException::class) + suspend fun `proteusNewPrekey`(`prekeyId`: UShort): List@Throws(CryptoException::class) + suspend fun `proteusNewPrekeyAuto`(): ProteusAutoPrekeyBundle@Throws(CryptoException::class) + suspend fun `proteusSessionDelete`(`sessionId`: String)@Throws(CryptoException::class) + suspend fun `proteusSessionExists`(`sessionId`: String): Boolean@Throws(CryptoException::class) + suspend fun `proteusSessionFromMessage`(`sessionId`: String, `envelope`: List): List@Throws(CryptoException::class) + suspend fun `proteusSessionFromPrekey`(`sessionId`: String, `prekey`: List)@Throws(CryptoException::class) + suspend fun `proteusSessionSave`(`sessionId`: String)@Throws(CryptoException::class) + suspend fun `randomBytes`(`len`: UInt): List@Throws(CryptoException::class) + suspend fun `removeClientsFromConversation`(`conversationId`: List, `clients`: List): CommitBundle@Throws(CryptoException::class) + suspend fun `reseedRng`(`seed`: List)@Throws(CryptoException::class) + suspend fun `restoreFromDisk`()@Throws(CryptoException::class) + suspend fun `setCallbacks`(`callbacks`: CoreCryptoCallbacks)@Throws(CryptoException::class) + suspend fun `unload`()@Throws(CryptoException::class) + suspend fun `updateKeyingMaterial`(`conversationId`: List): CommitBundle@Throws(CryptoException::class) + suspend fun `updateTrustAnchorsFromConversation`(`id`: List, `removeDomainNames`: List, `addTrustAnchors`: List): CommitBundle@Throws(CryptoException::class) + suspend fun `wipe`()@Throws(CryptoException::class) + suspend fun `wipeConversation`(`conversationId`: List) +} + +class CoreCrypto( + pointer: Pointer +) : FFIObject(pointer), CoreCryptoInterface { + + /** + * Disconnect the object from the underlying Rust object. + * + * It can be called more than once, but once called, interacting with the object + * causes an `IllegalStateException`. + * + * Clients **must** call this method once done with the object, or cause a memory leak. + */ + override protected fun freeRustArcPtr() { + rustCall() { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_free_corecrypto(this.pointer, status) + } + } + + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `addClientsToConversation`(`conversationId`: List, `clients`: List) : MemberAddedMessages { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeMemberAddedMessages_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeMemberAddedMessages_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_add_clients_to_conversation( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterSequenceTypeInvitee.lower(`clients`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `clearPendingCommit`(`conversationId`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_clear_pending_commit( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `clearPendingGroupFromExternalCommit`(`conversationId`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_clear_pending_group_from_external_commit( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `clearPendingProposal`(`conversationId`: List, `proposalRef`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_clear_pending_proposal( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterSequenceUByte.lower(`proposalRef`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `clientKeypackages`(`ciphersuite`: Ciphersuite, `credentialType`: MlsCredentialType, `amountRequested`: UInt) : List> { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_client_keypackages( + thisPtr, + FfiConverterTypeCiphersuite.lower(`ciphersuite`),FfiConverterTypeMlsCredentialType.lower(`credentialType`),FfiConverterUInt.lower(`amountRequested`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `clientPublicKey`(`ciphersuite`: Ciphersuite) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_client_public_key( + thisPtr, + FfiConverterTypeCiphersuite.lower(`ciphersuite`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `clientValidKeypackagesCount`(`ciphersuite`: Ciphersuite, `credentialType`: MlsCredentialType) : ULong { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerULong_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerULong_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_client_valid_keypackages_count( + thisPtr, + FfiConverterTypeCiphersuite.lower(`ciphersuite`),FfiConverterTypeMlsCredentialType.lower(`credentialType`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `commitAccepted`(`conversationId`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_commit_accepted( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `commitPendingProposals`(`conversationId`: List) : CommitBundle? { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerOptionalTypeCommitBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerOptionalTypeCommitBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_commit_pending_proposals( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `conversationEpoch`(`conversationId`: List) : ULong { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerULong_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerULong_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_conversation_epoch( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `conversationExists`(`conversationId`: List) : Boolean { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerBoolean? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerBoolean(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_conversation_exists( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `createConversation`(`conversationId`: List, `creatorCredentialType`: MlsCredentialType, `config`: ConversationConfiguration) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_create_conversation( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterTypeMlsCredentialType.lower(`creatorCredentialType`),FfiConverterTypeConversationConfiguration.lower(`config`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `decryptMessage`(`conversationId`: List, `payload`: List) : DecryptedMessage { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeDecryptedMessage_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeDecryptedMessage_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_decrypt_message( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterSequenceUByte.lower(`payload`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `deleteKeypackages`(`refs`: List>) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_delete_keypackages( + thisPtr, + FfiConverterSequenceSequenceUByte.lower(`refs`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiConversationState`(`conversationId`: List) : E2eiConversationState { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeE2eiConversationState_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeE2eiConversationState_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_conversation_state( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiEnrollmentStash`(`enrollment`: WireE2eIdentity) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_enrollment_stash( + thisPtr, + FfiConverterTypeWireE2eIdentity.lower(`enrollment`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiEnrollmentStashPop`(`handle`: List) : WireE2eIdentity { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_enrollment_stash_pop( + thisPtr, + FfiConverterSequenceUByte.lower(`handle`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiIsEnabled`(`ciphersuite`: Ciphersuite) : Boolean { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerBoolean_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerBoolean_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_is_enabled( + thisPtr, + FfiConverterTypeCiphersuite.lower(`ciphersuite`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiMlsInitOnly`(`enrollment`: WireE2eIdentity, `certificateChain`: String) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_mls_init_only( + thisPtr, + FfiConverterTypeWireE2eIdentity.lower(`enrollment`),FfiConverterString.lower(`certificateChain`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiNewActivationEnrollment`(`clientId`: String, `displayName`: String, `handle`: String, `expiryDays`: UInt, `ciphersuite`: Ciphersuite) : WireE2eIdentity { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_new_activation_enrollment( + thisPtr, + FfiConverterString.lower(`clientId`),FfiConverterString.lower(`displayName`),FfiConverterString.lower(`handle`),FfiConverterUInt.lower(`expiryDays`),FfiConverterTypeCiphersuite.lower(`ciphersuite`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiNewEnrollment`(`clientId`: String, `displayName`: String, `handle`: String, `expiryDays`: UInt, `ciphersuite`: Ciphersuite) : WireE2eIdentity { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_new_enrollment( + thisPtr, + FfiConverterString.lower(`clientId`),FfiConverterString.lower(`displayName`),FfiConverterString.lower(`handle`),FfiConverterUInt.lower(`expiryDays`),FfiConverterTypeCiphersuite.lower(`ciphersuite`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiNewRotateEnrollment`(`clientId`: String, `displayName`: String?, `handle`: String?, `expiryDays`: UInt, `ciphersuite`: Ciphersuite) : WireE2eIdentity { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_new_rotate_enrollment( + thisPtr, + FfiConverterString.lower(`clientId`),FfiConverterOptionalString.lower(`displayName`),FfiConverterOptionalString.lower(`handle`),FfiConverterUInt.lower(`expiryDays`),FfiConverterTypeCiphersuite.lower(`ciphersuite`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `e2eiRotateAll`(`enrollment`: WireE2eIdentity, `certificateChain`: String, `newKeyPackagesCount`: UInt) : RotateBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeRotateBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeRotateBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_e2ei_rotate_all( + thisPtr, + FfiConverterTypeWireE2eIdentity.lower(`enrollment`),FfiConverterString.lower(`certificateChain`),FfiConverterUInt.lower(`newKeyPackagesCount`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `encryptMessage`(`conversationId`: List, `message`: List) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_encrypt_message( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterSequenceUByte.lower(`message`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `exportSecretKey`(`conversationId`: List, `keyLength`: UInt) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_export_secret_key( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterUInt.lower(`keyLength`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getClientIds`(`conversationId`: List) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceTypeClientId_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceTypeClientId_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_get_client_ids( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `joinByExternalCommit`(`groupInfo`: List, `customConfiguration`: CustomConfiguration, `credentialType`: MlsCredentialType) : ConversationInitBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeConversationInitBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeConversationInitBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_join_by_external_commit( + thisPtr, + FfiConverterSequenceUByte.lower(`groupInfo`),FfiConverterTypeCustomConfiguration.lower(`customConfiguration`),FfiConverterTypeMlsCredentialType.lower(`credentialType`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `markConversationAsChildOf`(`childId`: List, `parentId`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_mark_conversation_as_child_of( + thisPtr, + FfiConverterSequenceUByte.lower(`childId`),FfiConverterSequenceUByte.lower(`parentId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `mergePendingGroupFromExternalCommit`(`conversationId`: List) : List? { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerOptionalSequenceTypeDecryptedMessage_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerOptionalSequenceTypeDecryptedMessage_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_merge_pending_group_from_external_commit( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `mlsGenerateKeypairs`(`ciphersuites`: Ciphersuites) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceTypeClientId_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceTypeClientId_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_mls_generate_keypairs( + thisPtr, + FfiConverterTypeCiphersuites.lower(`ciphersuites`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `mlsInit`(`clientId`: ClientId, `ciphersuites`: Ciphersuites) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_mls_init( + thisPtr, + FfiConverterTypeClientId.lower(`clientId`),FfiConverterTypeCiphersuites.lower(`ciphersuites`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `mlsInitWithClientId`(`clientId`: ClientId, `tmpClientIds`: List, `ciphersuites`: Ciphersuites) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_mls_init_with_client_id( + thisPtr, + FfiConverterTypeClientId.lower(`clientId`),FfiConverterSequenceTypeClientId.lower(`tmpClientIds`),FfiConverterTypeCiphersuites.lower(`ciphersuites`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newAddProposal`(`conversationId`: List, `keypackage`: List) : ProposalBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_new_add_proposal( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterSequenceUByte.lower(`keypackage`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newExternalAddProposal`(`conversationId`: List, `epoch`: ULong, `ciphersuite`: Ciphersuite, `credentialType`: MlsCredentialType) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_new_external_add_proposal( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterULong.lower(`epoch`),FfiConverterTypeCiphersuite.lower(`ciphersuite`),FfiConverterTypeMlsCredentialType.lower(`credentialType`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newRemoveProposal`(`conversationId`: List, `clientId`: ClientId) : ProposalBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_new_remove_proposal( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterTypeClientId.lower(`clientId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newUpdateProposal`(`conversationId`: List) : ProposalBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_new_update_proposal( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `processWelcomeMessage`(`welcomeMessage`: List, `customConfiguration`: CustomConfiguration) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_process_welcome_message( + thisPtr, + FfiConverterSequenceUByte.lower(`welcomeMessage`),FfiConverterTypeCustomConfiguration.lower(`customConfiguration`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusCryptoboxMigrate`(`path`: String) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_cryptobox_migrate( + thisPtr, + FfiConverterString.lower(`path`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusDecrypt`(`sessionId`: String, `ciphertext`: List) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_decrypt( + thisPtr, + FfiConverterString.lower(`sessionId`),FfiConverterSequenceUByte.lower(`ciphertext`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusEncrypt`(`sessionId`: String, `plaintext`: List) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_encrypt( + thisPtr, + FfiConverterString.lower(`sessionId`),FfiConverterSequenceUByte.lower(`plaintext`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusEncryptBatched`(`sessions`: List, `plaintext`: List) : Map> { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerMapStringSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerMapStringSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_encrypt_batched( + thisPtr, + FfiConverterSequenceString.lower(`sessions`),FfiConverterSequenceUByte.lower(`plaintext`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusFingerprint`() : String { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerString_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerString_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusFingerprintLocal`(`sessionId`: String) : String { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerString_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerString_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint_local( + thisPtr, + FfiConverterString.lower(`sessionId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class)override fun `proteusFingerprintPrekeybundle`(`prekey`: List): String = + callWithPointer { + rustCallWithError(CryptoException) { _status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint_prekeybundle(it, + FfiConverterSequenceUByte.lower(`prekey`), + _status) +} + }.let { + FfiConverterString.lift(it) + } + + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusFingerprintRemote`(`sessionId`: String) : String { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerString_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerString_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_fingerprint_remote( + thisPtr, + FfiConverterString.lower(`sessionId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusInit`() { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_init( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + override fun `proteusLastErrorCode`(): UInt = + callWithPointer { + rustCall() { _status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_last_error_code(it, + + _status) +} + }.let { + FfiConverterUInt.lift(it) + } + + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusLastResortPrekey`() : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_last_resort_prekey( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class)override fun `proteusLastResortPrekeyId`(): UShort = + callWithPointer { + rustCallWithError(CryptoException) { _status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_last_resort_prekey_id(it, + + _status) +} + }.let { + FfiConverterUShort.lift(it) + } + + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusNewPrekey`(`prekeyId`: UShort) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_new_prekey( + thisPtr, + FfiConverterUShort.lower(`prekeyId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusNewPrekeyAuto`() : ProteusAutoPrekeyBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeProteusAutoPrekeyBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeProteusAutoPrekeyBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_new_prekey_auto( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusSessionDelete`(`sessionId`: String) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_delete( + thisPtr, + FfiConverterString.lower(`sessionId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusSessionExists`(`sessionId`: String) : Boolean { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerBoolean_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerBoolean_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_exists( + thisPtr, + FfiConverterString.lower(`sessionId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusSessionFromMessage`(`sessionId`: String, `envelope`: List) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_from_message( + thisPtr, + FfiConverterString.lower(`sessionId`),FfiConverterSequenceUByte.lower(`envelope`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusSessionFromPrekey`(`sessionId`: String, `prekey`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_from_prekey( + thisPtr, + FfiConverterString.lower(`sessionId`),FfiConverterSequenceUByte.lower(`prekey`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `proteusSessionSave`(`sessionId`: String) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_proteus_session_save( + thisPtr, + FfiConverterString.lower(`sessionId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `randomBytes`(`len`: UInt) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_random_bytes( + thisPtr, + FfiConverterUInt.lower(`len`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `removeClientsFromConversation`(`conversationId`: List, `clients`: List) : CommitBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_remove_clients_from_conversation( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`),FfiConverterSequenceTypeClientId.lower(`clients`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `reseedRng`(`seed`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_reseed_rng( + thisPtr, + FfiConverterSequenceUByte.lower(`seed`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `restoreFromDisk`() { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_restore_from_disk( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `setCallbacks`(`callbacks`: CoreCryptoCallbacks) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_set_callbacks( + thisPtr, + FfiConverterTypeCoreCryptoCallbacks.lower(`callbacks`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `unload`() { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_unload( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `updateKeyingMaterial`(`conversationId`: List) : CommitBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_update_keying_material( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `updateTrustAnchorsFromConversation`(`id`: List, `removeDomainNames`: List, `addTrustAnchors`: List) : CommitBundle { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_update_trust_anchors_from_conversation( + thisPtr, + FfiConverterSequenceUByte.lower(`id`),FfiConverterSequenceString.lower(`removeDomainNames`),FfiConverterSequenceTypePerDomainTrustAnchor.lower(`addTrustAnchors`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `wipe`() { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_wipe( + thisPtr, + + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(CryptoException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `wipeConversation`(`conversationId`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeCryptoError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_corecrypto_wipe_conversation( + thisPtr, + FfiConverterSequenceUByte.lower(`conversationId`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + + +} + +public object FfiConverterTypeCoreCrypto: FfiConverter { + override fun lower(value: CoreCrypto): Pointer = value.callWithPointer { it } + + override fun lift(value: Pointer): CoreCrypto { + return CoreCrypto(value) + } + + override fun read(buf: ByteBuffer): CoreCrypto { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(Pointer(buf.getLong())) + } + + override fun allocationSize(value: CoreCrypto) = 8 + + override fun write(value: CoreCrypto, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(Pointer.nativeValue(lower(value))) + } +} + + + + +public interface WireE2eIdentityInterface { + @Throws(E2eIdentityException::class) + suspend fun `certificateRequest`(`previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `checkOrderRequest`(`orderUrl`: String, `previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `checkOrderResponse`(`order`: List): String@Throws(E2eIdentityException::class) + suspend fun `createDpopToken`(`expirySecs`: UInt, `backendNonce`: String): String@Throws(E2eIdentityException::class) + suspend fun `directoryResponse`(`directory`: List): AcmeDirectory@Throws(E2eIdentityException::class) + suspend fun `finalizeRequest`(`previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `finalizeResponse`(`finalize`: List): String@Throws(E2eIdentityException::class) + suspend fun `newAccountRequest`(`previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `newAccountResponse`(`account`: List)@Throws(E2eIdentityException::class) + suspend fun `newAuthzRequest`(`url`: String, `previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `newAuthzResponse`(`authz`: List): NewAcmeAuthz@Throws(E2eIdentityException::class) + suspend fun `newChallengeResponse`(`challenge`: List)@Throws(E2eIdentityException::class) + suspend fun `newDpopChallengeRequest`(`accessToken`: String, `previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `newOidcChallengeRequest`(`idToken`: String, `previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `newOrderRequest`(`previousNonce`: String): List@Throws(E2eIdentityException::class) + suspend fun `newOrderResponse`(`order`: List): NewAcmeOrder +} + +class WireE2eIdentity( + pointer: Pointer +) : FFIObject(pointer), WireE2eIdentityInterface { + + /** + * Disconnect the object from the underlying Rust object. + * + * It can be called more than once, but once called, interacting with the object + * causes an `IllegalStateException`. + * + * Clients **must** call this method once done with the object, or cause a memory leak. + */ + override protected fun freeRustArcPtr() { + rustCall() { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_free_wiree2eidentity(this.pointer, status) + } + } + + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `certificateRequest`(`previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_certificate_request( + thisPtr, + FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `checkOrderRequest`(`orderUrl`: String, `previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_check_order_request( + thisPtr, + FfiConverterString.lower(`orderUrl`),FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `checkOrderResponse`(`order`: List) : String { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerString_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerString_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_check_order_response( + thisPtr, + FfiConverterSequenceUByte.lower(`order`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `createDpopToken`(`expirySecs`: UInt, `backendNonce`: String) : String { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerString_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerString_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_create_dpop_token( + thisPtr, + FfiConverterUInt.lower(`expirySecs`),FfiConverterString.lower(`backendNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `directoryResponse`(`directory`: List) : AcmeDirectory { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeAcmeDirectory_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeAcmeDirectory_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_directory_response( + thisPtr, + FfiConverterSequenceUByte.lower(`directory`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `finalizeRequest`(`previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_finalize_request( + thisPtr, + FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `finalizeResponse`(`finalize`: List) : String { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerString_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerString_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_finalize_response( + thisPtr, + FfiConverterSequenceUByte.lower(`finalize`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newAccountRequest`(`previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_account_request( + thisPtr, + FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newAccountResponse`(`account`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_account_response( + thisPtr, + FfiConverterSequenceUByte.lower(`account`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newAuthzRequest`(`url`: String, `previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_authz_request( + thisPtr, + FfiConverterString.lower(`url`),FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newAuthzResponse`(`authz`: List) : NewAcmeAuthz { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeNewAcmeAuthz_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeNewAcmeAuthz_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_authz_response( + thisPtr, + FfiConverterSequenceUByte.lower(`authz`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newChallengeResponse`(`challenge`: List) { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerVoid_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerVoid_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_challenge_response( + thisPtr, + FfiConverterSequenceUByte.lower(`challenge`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newDpopChallengeRequest`(`accessToken`: String, `previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_dpop_challenge_request( + thisPtr, + FfiConverterString.lower(`accessToken`),FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newOidcChallengeRequest`(`idToken`: String, `previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_oidc_challenge_request( + thisPtr, + FfiConverterString.lower(`idToken`),FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newOrderRequest`(`previousNonce`: String) : List { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_order_request( + thisPtr, + FfiConverterString.lower(`previousNonce`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + @Throws(E2eIdentityException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `newOrderResponse`(`order`: List) : NewAcmeOrder { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeNewAcmeOrder_TypeE2eIdentityError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeNewAcmeOrder_TypeE2eIdentityError(continuation) + callbackHolder = callback + callWithPointer { thisPtr -> + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_method_wiree2eidentity_new_order_response( + thisPtr, + FfiConverterSequenceUByte.lower(`order`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } + } + + + +} + +public object FfiConverterTypeWireE2eIdentity: FfiConverter { + override fun lower(value: WireE2eIdentity): Pointer = value.callWithPointer { it } + + override fun lift(value: Pointer): WireE2eIdentity { + return WireE2eIdentity(value) + } + + override fun read(buf: ByteBuffer): WireE2eIdentity { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(Pointer(buf.getLong())) + } + + override fun allocationSize(value: WireE2eIdentity) = 8 + + override fun write(value: WireE2eIdentity, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(Pointer.nativeValue(lower(value))) + } +} + + + + + + +// Callback function to execute a Rust task. The Kotlin code schedules these in a coroutine then +// invokes them. +internal interface UniFfiRustTaskCallback : com.sun.jna.Callback { + fun invoke(rustTaskData: Pointer?) +} + +object UniFfiForeignExecutorCallback : com.sun.jna.Callback { + internal fun invoke(handle: USize, delayMs: Int, rustTask: UniFfiRustTaskCallback?, rustTaskData: Pointer?) { + if (rustTask == null) { + FfiConverterForeignExecutor.drop(handle) + } else { + val coroutineScope = FfiConverterForeignExecutor.lift(handle) + coroutineScope.launch { + if (delayMs > 0) { + delay(delayMs.toLong()) + } + rustTask.invoke(rustTaskData) + } + } + } +} + +public object FfiConverterForeignExecutor: FfiConverter { + internal val handleMap = UniFfiHandleMap() + + internal fun drop(handle: USize) { + handleMap.remove(handle) + } + + internal fun register(lib: _UniFFILib) { + lib.uniffi_foreign_executor_callback_set(UniFfiForeignExecutorCallback) + } + + // Number of live handles, exposed so we can test the memory management + public fun handleCount() : Int { + return handleMap.size + } + + override fun allocationSize(value: CoroutineScope) = USize.size + + override fun lift(value: USize): CoroutineScope { + return handleMap.get(value) ?: throw RuntimeException("unknown handle in FfiConverterForeignExecutor.lift") + } + + override fun read(buf: ByteBuffer): CoroutineScope { + return lift(USize.readFromBuffer(buf)) + } + + override fun lower(value: CoroutineScope): USize { + return handleMap.insert(value) + } + + override fun write(value: CoroutineScope, buf: ByteBuffer) { + lower(value).writeToBuffer(buf) + } +} + + + + +data class AcmeChallenge ( + var `delegate`: ByteArray, + var `url`: String, + var `target`: String +) { + +} + +public object FfiConverterTypeAcmeChallenge: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AcmeChallenge { + return AcmeChallenge( + FfiConverterByteArray.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: AcmeChallenge) = ( + FfiConverterByteArray.allocationSize(value.`delegate`) + + FfiConverterString.allocationSize(value.`url`) + + FfiConverterString.allocationSize(value.`target`) + ) + + override fun write(value: AcmeChallenge, buf: ByteBuffer) { + FfiConverterByteArray.write(value.`delegate`, buf) + FfiConverterString.write(value.`url`, buf) + FfiConverterString.write(value.`target`, buf) + } +} + + + + +data class AcmeDirectory ( + var `newNonce`: String, + var `newAccount`: String, + var `newOrder`: String +) { + +} + +public object FfiConverterTypeAcmeDirectory: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AcmeDirectory { + return AcmeDirectory( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: AcmeDirectory) = ( + FfiConverterString.allocationSize(value.`newNonce`) + + FfiConverterString.allocationSize(value.`newAccount`) + + FfiConverterString.allocationSize(value.`newOrder`) + ) + + override fun write(value: AcmeDirectory, buf: ByteBuffer) { + FfiConverterString.write(value.`newNonce`, buf) + FfiConverterString.write(value.`newAccount`, buf) + FfiConverterString.write(value.`newOrder`, buf) + } +} + + + + +data class CommitBundle ( + var `welcome`: ByteArray?, + var `commit`: ByteArray, + var `groupInfo`: GroupInfoBundle +) { + +} + +public object FfiConverterTypeCommitBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CommitBundle { + return CommitBundle( + FfiConverterOptionalByteArray.read(buf), + FfiConverterByteArray.read(buf), + FfiConverterTypeGroupInfoBundle.read(buf), + ) + } + + override fun allocationSize(value: CommitBundle) = ( + FfiConverterOptionalByteArray.allocationSize(value.`welcome`) + + FfiConverterByteArray.allocationSize(value.`commit`) + + FfiConverterTypeGroupInfoBundle.allocationSize(value.`groupInfo`) + ) + + override fun write(value: CommitBundle, buf: ByteBuffer) { + FfiConverterOptionalByteArray.write(value.`welcome`, buf) + FfiConverterByteArray.write(value.`commit`, buf) + FfiConverterTypeGroupInfoBundle.write(value.`groupInfo`, buf) + } +} + + + + +data class ConversationConfiguration ( + var `ciphersuite`: Ciphersuite, + var `externalSenders`: List, + var `custom`: CustomConfiguration, + var `perDomainTrustAnchors`: List +) { + +} + +public object FfiConverterTypeConversationConfiguration: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ConversationConfiguration { + return ConversationConfiguration( + FfiConverterTypeCiphersuite.read(buf), + FfiConverterSequenceByteArray.read(buf), + FfiConverterTypeCustomConfiguration.read(buf), + FfiConverterSequenceTypePerDomainTrustAnchor.read(buf), + ) + } + + override fun allocationSize(value: ConversationConfiguration) = ( + FfiConverterTypeCiphersuite.allocationSize(value.`ciphersuite`) + + FfiConverterSequenceByteArray.allocationSize(value.`externalSenders`) + + FfiConverterTypeCustomConfiguration.allocationSize(value.`custom`) + + FfiConverterSequenceTypePerDomainTrustAnchor.allocationSize(value.`perDomainTrustAnchors`) + ) + + override fun write(value: ConversationConfiguration, buf: ByteBuffer) { + FfiConverterTypeCiphersuite.write(value.`ciphersuite`, buf) + FfiConverterSequenceByteArray.write(value.`externalSenders`, buf) + FfiConverterTypeCustomConfiguration.write(value.`custom`, buf) + FfiConverterSequenceTypePerDomainTrustAnchor.write(value.`perDomainTrustAnchors`, buf) + } +} + + + + +data class ConversationInitBundle ( + var `conversationId`: ByteArray, + var `commit`: ByteArray, + var `groupInfo`: GroupInfoBundle +) { + +} + +public object FfiConverterTypeConversationInitBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ConversationInitBundle { + return ConversationInitBundle( + FfiConverterByteArray.read(buf), + FfiConverterByteArray.read(buf), + FfiConverterTypeGroupInfoBundle.read(buf), + ) + } + + override fun allocationSize(value: ConversationInitBundle) = ( + FfiConverterByteArray.allocationSize(value.`conversationId`) + + FfiConverterByteArray.allocationSize(value.`commit`) + + FfiConverterTypeGroupInfoBundle.allocationSize(value.`groupInfo`) + ) + + override fun write(value: ConversationInitBundle, buf: ByteBuffer) { + FfiConverterByteArray.write(value.`conversationId`, buf) + FfiConverterByteArray.write(value.`commit`, buf) + FfiConverterTypeGroupInfoBundle.write(value.`groupInfo`, buf) + } +} + + + + +data class CustomConfiguration ( + var `keyRotationSpan`: java.time.Duration?, + var `wirePolicy`: MlsWirePolicy? +) { + +} + +public object FfiConverterTypeCustomConfiguration: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CustomConfiguration { + return CustomConfiguration( + FfiConverterOptionalDuration.read(buf), + FfiConverterOptionalTypeMlsWirePolicy.read(buf), + ) + } + + override fun allocationSize(value: CustomConfiguration) = ( + FfiConverterOptionalDuration.allocationSize(value.`keyRotationSpan`) + + FfiConverterOptionalTypeMlsWirePolicy.allocationSize(value.`wirePolicy`) + ) + + override fun write(value: CustomConfiguration, buf: ByteBuffer) { + FfiConverterOptionalDuration.write(value.`keyRotationSpan`, buf) + FfiConverterOptionalTypeMlsWirePolicy.write(value.`wirePolicy`, buf) + } +} + + + + +data class DecryptedMessage ( + var `message`: ByteArray?, + var `proposals`: List, + var `isActive`: Boolean, + var `commitDelay`: ULong?, + var `senderClientId`: ClientId?, + var `hasEpochChanged`: Boolean, + var `identity`: WireIdentity? +) { + +} + +public object FfiConverterTypeDecryptedMessage: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): DecryptedMessage { + return DecryptedMessage( + FfiConverterOptionalByteArray.read(buf), + FfiConverterSequenceTypeProposalBundle.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalTypeClientId.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterOptionalTypeWireIdentity.read(buf), + ) + } + + override fun allocationSize(value: DecryptedMessage) = ( + FfiConverterOptionalByteArray.allocationSize(value.`message`) + + FfiConverterSequenceTypeProposalBundle.allocationSize(value.`proposals`) + + FfiConverterBoolean.allocationSize(value.`isActive`) + + FfiConverterOptionalULong.allocationSize(value.`commitDelay`) + + FfiConverterOptionalTypeClientId.allocationSize(value.`senderClientId`) + + FfiConverterBoolean.allocationSize(value.`hasEpochChanged`) + + FfiConverterOptionalTypeWireIdentity.allocationSize(value.`identity`) + ) + + override fun write(value: DecryptedMessage, buf: ByteBuffer) { + FfiConverterOptionalByteArray.write(value.`message`, buf) + FfiConverterSequenceTypeProposalBundle.write(value.`proposals`, buf) + FfiConverterBoolean.write(value.`isActive`, buf) + FfiConverterOptionalULong.write(value.`commitDelay`, buf) + FfiConverterOptionalTypeClientId.write(value.`senderClientId`, buf) + FfiConverterBoolean.write(value.`hasEpochChanged`, buf) + FfiConverterOptionalTypeWireIdentity.write(value.`identity`, buf) + } +} + + + + +data class GroupInfoBundle ( + var `encryptionType`: MlsGroupInfoEncryptionType, + var `ratchetTreeType`: MlsRatchetTreeType, + var `payload`: ByteArray +) { + +} + +public object FfiConverterTypeGroupInfoBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): GroupInfoBundle { + return GroupInfoBundle( + FfiConverterTypeMlsGroupInfoEncryptionType.read(buf), + FfiConverterTypeMlsRatchetTreeType.read(buf), + FfiConverterByteArray.read(buf), + ) + } + + override fun allocationSize(value: GroupInfoBundle) = ( + FfiConverterTypeMlsGroupInfoEncryptionType.allocationSize(value.`encryptionType`) + + FfiConverterTypeMlsRatchetTreeType.allocationSize(value.`ratchetTreeType`) + + FfiConverterByteArray.allocationSize(value.`payload`) + ) + + override fun write(value: GroupInfoBundle, buf: ByteBuffer) { + FfiConverterTypeMlsGroupInfoEncryptionType.write(value.`encryptionType`, buf) + FfiConverterTypeMlsRatchetTreeType.write(value.`ratchetTreeType`, buf) + FfiConverterByteArray.write(value.`payload`, buf) + } +} + + + + +data class Invitee ( + var `id`: ClientId, + var `kp`: ByteArray +) { + +} + +public object FfiConverterTypeInvitee: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Invitee { + return Invitee( + FfiConverterTypeClientId.read(buf), + FfiConverterByteArray.read(buf), + ) + } + + override fun allocationSize(value: Invitee) = ( + FfiConverterTypeClientId.allocationSize(value.`id`) + + FfiConverterByteArray.allocationSize(value.`kp`) + ) + + override fun write(value: Invitee, buf: ByteBuffer) { + FfiConverterTypeClientId.write(value.`id`, buf) + FfiConverterByteArray.write(value.`kp`, buf) + } +} + + + + +data class MemberAddedMessages ( + var `commit`: ByteArray, + var `welcome`: ByteArray, + var `groupInfo`: GroupInfoBundle +) { + +} + +public object FfiConverterTypeMemberAddedMessages: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): MemberAddedMessages { + return MemberAddedMessages( + FfiConverterByteArray.read(buf), + FfiConverterByteArray.read(buf), + FfiConverterTypeGroupInfoBundle.read(buf), + ) + } + + override fun allocationSize(value: MemberAddedMessages) = ( + FfiConverterByteArray.allocationSize(value.`commit`) + + FfiConverterByteArray.allocationSize(value.`welcome`) + + FfiConverterTypeGroupInfoBundle.allocationSize(value.`groupInfo`) + ) + + override fun write(value: MemberAddedMessages, buf: ByteBuffer) { + FfiConverterByteArray.write(value.`commit`, buf) + FfiConverterByteArray.write(value.`welcome`, buf) + FfiConverterTypeGroupInfoBundle.write(value.`groupInfo`, buf) + } +} + + + + +data class NewAcmeAuthz ( + var `identifier`: String, + var `wireDpopChallenge`: AcmeChallenge?, + var `wireOidcChallenge`: AcmeChallenge? +) { + +} + +public object FfiConverterTypeNewAcmeAuthz: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NewAcmeAuthz { + return NewAcmeAuthz( + FfiConverterString.read(buf), + FfiConverterOptionalTypeAcmeChallenge.read(buf), + FfiConverterOptionalTypeAcmeChallenge.read(buf), + ) + } + + override fun allocationSize(value: NewAcmeAuthz) = ( + FfiConverterString.allocationSize(value.`identifier`) + + FfiConverterOptionalTypeAcmeChallenge.allocationSize(value.`wireDpopChallenge`) + + FfiConverterOptionalTypeAcmeChallenge.allocationSize(value.`wireOidcChallenge`) + ) + + override fun write(value: NewAcmeAuthz, buf: ByteBuffer) { + FfiConverterString.write(value.`identifier`, buf) + FfiConverterOptionalTypeAcmeChallenge.write(value.`wireDpopChallenge`, buf) + FfiConverterOptionalTypeAcmeChallenge.write(value.`wireOidcChallenge`, buf) + } +} + + + + +data class NewAcmeOrder ( + var `delegate`: ByteArray, + var `authorizations`: List +) { + +} + +public object FfiConverterTypeNewAcmeOrder: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): NewAcmeOrder { + return NewAcmeOrder( + FfiConverterByteArray.read(buf), + FfiConverterSequenceString.read(buf), + ) + } + + override fun allocationSize(value: NewAcmeOrder) = ( + FfiConverterByteArray.allocationSize(value.`delegate`) + + FfiConverterSequenceString.allocationSize(value.`authorizations`) + ) + + override fun write(value: NewAcmeOrder, buf: ByteBuffer) { + FfiConverterByteArray.write(value.`delegate`, buf) + FfiConverterSequenceString.write(value.`authorizations`, buf) + } +} + + + + +data class PerDomainTrustAnchor ( + var `domainName`: String, + var `intermediateCertificateChain`: String +) { + +} + +public object FfiConverterTypePerDomainTrustAnchor: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PerDomainTrustAnchor { + return PerDomainTrustAnchor( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: PerDomainTrustAnchor) = ( + FfiConverterString.allocationSize(value.`domainName`) + + FfiConverterString.allocationSize(value.`intermediateCertificateChain`) + ) + + override fun write(value: PerDomainTrustAnchor, buf: ByteBuffer) { + FfiConverterString.write(value.`domainName`, buf) + FfiConverterString.write(value.`intermediateCertificateChain`, buf) + } +} + + + + +data class ProposalBundle ( + var `proposal`: ByteArray, + var `proposalRef`: ByteArray +) { + +} + +public object FfiConverterTypeProposalBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ProposalBundle { + return ProposalBundle( + FfiConverterByteArray.read(buf), + FfiConverterByteArray.read(buf), + ) + } + + override fun allocationSize(value: ProposalBundle) = ( + FfiConverterByteArray.allocationSize(value.`proposal`) + + FfiConverterByteArray.allocationSize(value.`proposalRef`) + ) + + override fun write(value: ProposalBundle, buf: ByteBuffer) { + FfiConverterByteArray.write(value.`proposal`, buf) + FfiConverterByteArray.write(value.`proposalRef`, buf) + } +} + + + + +data class ProteusAutoPrekeyBundle ( + var `id`: UShort, + var `pkb`: ByteArray +) { + +} + +public object FfiConverterTypeProteusAutoPrekeyBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ProteusAutoPrekeyBundle { + return ProteusAutoPrekeyBundle( + FfiConverterUShort.read(buf), + FfiConverterByteArray.read(buf), + ) + } + + override fun allocationSize(value: ProteusAutoPrekeyBundle) = ( + FfiConverterUShort.allocationSize(value.`id`) + + FfiConverterByteArray.allocationSize(value.`pkb`) + ) + + override fun write(value: ProteusAutoPrekeyBundle, buf: ByteBuffer) { + FfiConverterUShort.write(value.`id`, buf) + FfiConverterByteArray.write(value.`pkb`, buf) + } +} + + + + +data class RotateBundle ( + var `commits`: List, + var `newKeyPackages`: List, + var `keyPackageRefsToRemove`: List +) { + +} + +public object FfiConverterTypeRotateBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RotateBundle { + return RotateBundle( + FfiConverterSequenceTypeCommitBundle.read(buf), + FfiConverterSequenceByteArray.read(buf), + FfiConverterSequenceByteArray.read(buf), + ) + } + + override fun allocationSize(value: RotateBundle) = ( + FfiConverterSequenceTypeCommitBundle.allocationSize(value.`commits`) + + FfiConverterSequenceByteArray.allocationSize(value.`newKeyPackages`) + + FfiConverterSequenceByteArray.allocationSize(value.`keyPackageRefsToRemove`) + ) + + override fun write(value: RotateBundle, buf: ByteBuffer) { + FfiConverterSequenceTypeCommitBundle.write(value.`commits`, buf) + FfiConverterSequenceByteArray.write(value.`newKeyPackages`, buf) + FfiConverterSequenceByteArray.write(value.`keyPackageRefsToRemove`, buf) + } +} + + + + +data class WireIdentity ( + var `clientId`: String, + var `handle`: String, + var `displayName`: String, + var `domain`: String +) { + +} + +public object FfiConverterTypeWireIdentity: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): WireIdentity { + return WireIdentity( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), + ) + } + + override fun allocationSize(value: WireIdentity) = ( + FfiConverterString.allocationSize(value.`clientId`) + + FfiConverterString.allocationSize(value.`handle`) + + FfiConverterString.allocationSize(value.`displayName`) + + FfiConverterString.allocationSize(value.`domain`) + ) + + override fun write(value: WireIdentity, buf: ByteBuffer) { + FfiConverterString.write(value.`clientId`, buf) + FfiConverterString.write(value.`handle`, buf) + FfiConverterString.write(value.`displayName`, buf) + FfiConverterString.write(value.`domain`, buf) + } +} + + + + +enum class CiphersuiteName { + MLS_128_DHKEMX25519_AES128GCM_SHA256_ED25519,MLS_128_DHKEMP256_AES128GCM_SHA256_P256,MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_ED25519,MLS_256_DHKEMX448_AES256GCM_SHA512_ED448,MLS_256_DHKEMP521_AES256GCM_SHA512_P521,MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_ED448,MLS_256_DHKEMP384_AES256GCM_SHA384_P384,MLS_128_X25519KYBER768DRAFT00_AES128GCM_SHA256_ED25519; +} + +public object FfiConverterTypeCiphersuiteName: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + CiphersuiteName.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: CiphersuiteName) = 4 + + override fun write(value: CiphersuiteName, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + + +sealed class CryptoException(message: String): Exception(message) { + // Each variant is a nested class + // Flat enums carries a string error message, so no special implementation is necessary. + class ConversationNotFound(message: String) : CryptoException(message) + class ConversationAlreadyExists(message: String) : CryptoException(message) + class ClientNotFound(message: String) : CryptoException(message) + class PendingProposalNotFound(message: String) : CryptoException(message) + class PendingCommitNotFound(message: String) : CryptoException(message) + class MalformedIdentifier(message: String) : CryptoException(message) + class ClientSignatureNotFound(message: String) : CryptoException(message) + class LockPoisonException(message: String) : CryptoException(message) + class ImplementationException(message: String) : CryptoException(message) + class OutOfKeyPackage(message: String) : CryptoException(message) + class MlsProviderException(message: String) : CryptoException(message) + class KeyStoreException(message: String) : CryptoException(message) + class MlsException(message: String) : CryptoException(message) + class Utf8Exception(message: String) : CryptoException(message) + class StringUtf8Exception(message: String) : CryptoException(message) + class ParseIntException(message: String) : CryptoException(message) + class ConvertIntException(message: String) : CryptoException(message) + class InvalidByteArrayException(message: String) : CryptoException(message) + class IoException(message: String) : CryptoException(message) + class Unauthorized(message: String) : CryptoException(message) + class CallbacksNotSet(message: String) : CryptoException(message) + class UnauthorizedExternalAddProposal(message: String) : CryptoException(message) + class UnauthorizedExternalCommit(message: String) : CryptoException(message) + class InvalidHashReference(message: String) : CryptoException(message) + class DuplicateMessage(message: String) : CryptoException(message) + class WrongEpoch(message: String) : CryptoException(message) + class DecryptionException(message: String) : CryptoException(message) + class HexDecodeException(message: String) : CryptoException(message) + class ProteusException(message: String) : CryptoException(message) + class CryptoboxMigrationException(message: String) : CryptoException(message) + class ProteusNotInitialized(message: String) : CryptoException(message) + class ProteusSupportNotEnabled(message: String) : CryptoException(message) + class MlsNotInitialized(message: String) : CryptoException(message) + class InvalidKeyPackage(message: String) : CryptoException(message) + class IdentityAlreadyPresent(message: String) : CryptoException(message) + class NoProvisionalIdentityFound(message: String) : CryptoException(message) + class TooManyIdentitiesPresent(message: String) : CryptoException(message) + class ParentGroupNotFound(message: String) : CryptoException(message) + class InvalidIdentity(message: String) : CryptoException(message) + class IdentityInitializationException(message: String) : CryptoException(message) + class MessageEpochTooOld(message: String) : CryptoException(message) + class E2eiEnrollmentNotDone(message: String) : CryptoException(message) + class CredentialNotFound(message: String) : CryptoException(message) + class InternalMlsException(message: String) : CryptoException(message) + class ClearingPendingCommitException(message: String) : CryptoException(message) + class SelfCommitIgnored(message: String) : CryptoException(message) + class UnmergedPendingGroup(message: String) : CryptoException(message) + class X509CertDerException(message: String) : CryptoException(message) + class PemException(message: String) : CryptoException(message) + class DomainNameNotFound(message: String) : CryptoException(message) + class DomainNamesDontMatch(message: String) : CryptoException(message) + class DuplicateDomainName(message: String) : CryptoException(message) + class InvalidCertificateChain(message: String) : CryptoException(message) + class EmptyTrustAnchorUpdate(message: String) : CryptoException(message) + class DuplicateCertificateChain(message: String) : CryptoException(message) + class OrphanWelcome(message: String) : CryptoException(message) + + + companion object ErrorHandler : CallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): CryptoException = FfiConverterTypeCryptoError.lift(error_buf) + } +} + +public object FfiConverterTypeCryptoError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CryptoException { + + return when(buf.getInt()) { + 1 -> CryptoException.ConversationNotFound(FfiConverterString.read(buf)) + 2 -> CryptoException.ConversationAlreadyExists(FfiConverterString.read(buf)) + 3 -> CryptoException.ClientNotFound(FfiConverterString.read(buf)) + 4 -> CryptoException.PendingProposalNotFound(FfiConverterString.read(buf)) + 5 -> CryptoException.PendingCommitNotFound(FfiConverterString.read(buf)) + 6 -> CryptoException.MalformedIdentifier(FfiConverterString.read(buf)) + 7 -> CryptoException.ClientSignatureNotFound(FfiConverterString.read(buf)) + 8 -> CryptoException.LockPoisonException(FfiConverterString.read(buf)) + 9 -> CryptoException.ImplementationException(FfiConverterString.read(buf)) + 10 -> CryptoException.OutOfKeyPackage(FfiConverterString.read(buf)) + 11 -> CryptoException.MlsProviderException(FfiConverterString.read(buf)) + 12 -> CryptoException.KeyStoreException(FfiConverterString.read(buf)) + 13 -> CryptoException.MlsException(FfiConverterString.read(buf)) + 14 -> CryptoException.Utf8Exception(FfiConverterString.read(buf)) + 15 -> CryptoException.StringUtf8Exception(FfiConverterString.read(buf)) + 16 -> CryptoException.ParseIntException(FfiConverterString.read(buf)) + 17 -> CryptoException.ConvertIntException(FfiConverterString.read(buf)) + 18 -> CryptoException.InvalidByteArrayException(FfiConverterString.read(buf)) + 19 -> CryptoException.IoException(FfiConverterString.read(buf)) + 20 -> CryptoException.Unauthorized(FfiConverterString.read(buf)) + 21 -> CryptoException.CallbacksNotSet(FfiConverterString.read(buf)) + 22 -> CryptoException.UnauthorizedExternalAddProposal(FfiConverterString.read(buf)) + 23 -> CryptoException.UnauthorizedExternalCommit(FfiConverterString.read(buf)) + 24 -> CryptoException.InvalidHashReference(FfiConverterString.read(buf)) + 25 -> CryptoException.DuplicateMessage(FfiConverterString.read(buf)) + 26 -> CryptoException.WrongEpoch(FfiConverterString.read(buf)) + 27 -> CryptoException.DecryptionException(FfiConverterString.read(buf)) + 28 -> CryptoException.HexDecodeException(FfiConverterString.read(buf)) + 29 -> CryptoException.ProteusException(FfiConverterString.read(buf)) + 30 -> CryptoException.CryptoboxMigrationException(FfiConverterString.read(buf)) + 31 -> CryptoException.ProteusNotInitialized(FfiConverterString.read(buf)) + 32 -> CryptoException.ProteusSupportNotEnabled(FfiConverterString.read(buf)) + 33 -> CryptoException.MlsNotInitialized(FfiConverterString.read(buf)) + 34 -> CryptoException.InvalidKeyPackage(FfiConverterString.read(buf)) + 35 -> CryptoException.IdentityAlreadyPresent(FfiConverterString.read(buf)) + 36 -> CryptoException.NoProvisionalIdentityFound(FfiConverterString.read(buf)) + 37 -> CryptoException.TooManyIdentitiesPresent(FfiConverterString.read(buf)) + 38 -> CryptoException.ParentGroupNotFound(FfiConverterString.read(buf)) + 39 -> CryptoException.InvalidIdentity(FfiConverterString.read(buf)) + 40 -> CryptoException.IdentityInitializationException(FfiConverterString.read(buf)) + 41 -> CryptoException.MessageEpochTooOld(FfiConverterString.read(buf)) + 42 -> CryptoException.E2eiEnrollmentNotDone(FfiConverterString.read(buf)) + 43 -> CryptoException.CredentialNotFound(FfiConverterString.read(buf)) + 44 -> CryptoException.InternalMlsException(FfiConverterString.read(buf)) + 45 -> CryptoException.ClearingPendingCommitException(FfiConverterString.read(buf)) + 46 -> CryptoException.SelfCommitIgnored(FfiConverterString.read(buf)) + 47 -> CryptoException.UnmergedPendingGroup(FfiConverterString.read(buf)) + 48 -> CryptoException.X509CertDerException(FfiConverterString.read(buf)) + 49 -> CryptoException.PemException(FfiConverterString.read(buf)) + 50 -> CryptoException.DomainNameNotFound(FfiConverterString.read(buf)) + 51 -> CryptoException.DomainNamesDontMatch(FfiConverterString.read(buf)) + 52 -> CryptoException.DuplicateDomainName(FfiConverterString.read(buf)) + 53 -> CryptoException.InvalidCertificateChain(FfiConverterString.read(buf)) + 54 -> CryptoException.EmptyTrustAnchorUpdate(FfiConverterString.read(buf)) + 55 -> CryptoException.DuplicateCertificateChain(FfiConverterString.read(buf)) + 56 -> CryptoException.OrphanWelcome(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + + } + + override fun allocationSize(value: CryptoException): Int { + return 4 + } + + override fun write(value: CryptoException, buf: ByteBuffer) { + when(value) { + is CryptoException.ConversationNotFound -> { + buf.putInt(1) + Unit + } + is CryptoException.ConversationAlreadyExists -> { + buf.putInt(2) + Unit + } + is CryptoException.ClientNotFound -> { + buf.putInt(3) + Unit + } + is CryptoException.PendingProposalNotFound -> { + buf.putInt(4) + Unit + } + is CryptoException.PendingCommitNotFound -> { + buf.putInt(5) + Unit + } + is CryptoException.MalformedIdentifier -> { + buf.putInt(6) + Unit + } + is CryptoException.ClientSignatureNotFound -> { + buf.putInt(7) + Unit + } + is CryptoException.LockPoisonException -> { + buf.putInt(8) + Unit + } + is CryptoException.ImplementationException -> { + buf.putInt(9) + Unit + } + is CryptoException.OutOfKeyPackage -> { + buf.putInt(10) + Unit + } + is CryptoException.MlsProviderException -> { + buf.putInt(11) + Unit + } + is CryptoException.KeyStoreException -> { + buf.putInt(12) + Unit + } + is CryptoException.MlsException -> { + buf.putInt(13) + Unit + } + is CryptoException.Utf8Exception -> { + buf.putInt(14) + Unit + } + is CryptoException.StringUtf8Exception -> { + buf.putInt(15) + Unit + } + is CryptoException.ParseIntException -> { + buf.putInt(16) + Unit + } + is CryptoException.ConvertIntException -> { + buf.putInt(17) + Unit + } + is CryptoException.InvalidByteArrayException -> { + buf.putInt(18) + Unit + } + is CryptoException.IoException -> { + buf.putInt(19) + Unit + } + is CryptoException.Unauthorized -> { + buf.putInt(20) + Unit + } + is CryptoException.CallbacksNotSet -> { + buf.putInt(21) + Unit + } + is CryptoException.UnauthorizedExternalAddProposal -> { + buf.putInt(22) + Unit + } + is CryptoException.UnauthorizedExternalCommit -> { + buf.putInt(23) + Unit + } + is CryptoException.InvalidHashReference -> { + buf.putInt(24) + Unit + } + is CryptoException.DuplicateMessage -> { + buf.putInt(25) + Unit + } + is CryptoException.WrongEpoch -> { + buf.putInt(26) + Unit + } + is CryptoException.DecryptionException -> { + buf.putInt(27) + Unit + } + is CryptoException.HexDecodeException -> { + buf.putInt(28) + Unit + } + is CryptoException.ProteusException -> { + buf.putInt(29) + Unit + } + is CryptoException.CryptoboxMigrationException -> { + buf.putInt(30) + Unit + } + is CryptoException.ProteusNotInitialized -> { + buf.putInt(31) + Unit + } + is CryptoException.ProteusSupportNotEnabled -> { + buf.putInt(32) + Unit + } + is CryptoException.MlsNotInitialized -> { + buf.putInt(33) + Unit + } + is CryptoException.InvalidKeyPackage -> { + buf.putInt(34) + Unit + } + is CryptoException.IdentityAlreadyPresent -> { + buf.putInt(35) + Unit + } + is CryptoException.NoProvisionalIdentityFound -> { + buf.putInt(36) + Unit + } + is CryptoException.TooManyIdentitiesPresent -> { + buf.putInt(37) + Unit + } + is CryptoException.ParentGroupNotFound -> { + buf.putInt(38) + Unit + } + is CryptoException.InvalidIdentity -> { + buf.putInt(39) + Unit + } + is CryptoException.IdentityInitializationException -> { + buf.putInt(40) + Unit + } + is CryptoException.MessageEpochTooOld -> { + buf.putInt(41) + Unit + } + is CryptoException.E2eiEnrollmentNotDone -> { + buf.putInt(42) + Unit + } + is CryptoException.CredentialNotFound -> { + buf.putInt(43) + Unit + } + is CryptoException.InternalMlsException -> { + buf.putInt(44) + Unit + } + is CryptoException.ClearingPendingCommitException -> { + buf.putInt(45) + Unit + } + is CryptoException.SelfCommitIgnored -> { + buf.putInt(46) + Unit + } + is CryptoException.UnmergedPendingGroup -> { + buf.putInt(47) + Unit + } + is CryptoException.X509CertDerException -> { + buf.putInt(48) + Unit + } + is CryptoException.PemException -> { + buf.putInt(49) + Unit + } + is CryptoException.DomainNameNotFound -> { + buf.putInt(50) + Unit + } + is CryptoException.DomainNamesDontMatch -> { + buf.putInt(51) + Unit + } + is CryptoException.DuplicateDomainName -> { + buf.putInt(52) + Unit + } + is CryptoException.InvalidCertificateChain -> { + buf.putInt(53) + Unit + } + is CryptoException.EmptyTrustAnchorUpdate -> { + buf.putInt(54) + Unit + } + is CryptoException.DuplicateCertificateChain -> { + buf.putInt(55) + Unit + } + is CryptoException.OrphanWelcome -> { + buf.putInt(56) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } + +} + + + + + +sealed class E2eIdentityException(message: String): Exception(message) { + // Each variant is a nested class + // Flat enums carries a string error message, so no special implementation is necessary. + class ImplementationException(message: String) : E2eIdentityException(message) + class NotYetSupported(message: String) : E2eIdentityException(message) + class E2eiInvalidDomain(message: String) : E2eIdentityException(message) + class CryptoException(message: String) : E2eIdentityException(message) + class IdentityException(message: String) : E2eIdentityException(message) + class UrlException(message: String) : E2eIdentityException(message) + class JsonException(message: String) : E2eIdentityException(message) + class Utf8Exception(message: String) : E2eIdentityException(message) + class MlsException(message: String) : E2eIdentityException(message) + class LockPoisonException(message: String) : E2eIdentityException(message) + + + companion object ErrorHandler : CallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): E2eIdentityException = FfiConverterTypeE2eIdentityError.lift(error_buf) + } +} + +public object FfiConverterTypeE2eIdentityError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): E2eIdentityException { + + return when(buf.getInt()) { + 1 -> E2eIdentityException.ImplementationException(FfiConverterString.read(buf)) + 2 -> E2eIdentityException.NotYetSupported(FfiConverterString.read(buf)) + 3 -> E2eIdentityException.E2eiInvalidDomain(FfiConverterString.read(buf)) + 4 -> E2eIdentityException.CryptoException(FfiConverterString.read(buf)) + 5 -> E2eIdentityException.IdentityException(FfiConverterString.read(buf)) + 6 -> E2eIdentityException.UrlException(FfiConverterString.read(buf)) + 7 -> E2eIdentityException.JsonException(FfiConverterString.read(buf)) + 8 -> E2eIdentityException.Utf8Exception(FfiConverterString.read(buf)) + 9 -> E2eIdentityException.MlsException(FfiConverterString.read(buf)) + 10 -> E2eIdentityException.LockPoisonException(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + + } + + override fun allocationSize(value: E2eIdentityException): Int { + return 4 + } + + override fun write(value: E2eIdentityException, buf: ByteBuffer) { + when(value) { + is E2eIdentityException.ImplementationException -> { + buf.putInt(1) + Unit + } + is E2eIdentityException.NotYetSupported -> { + buf.putInt(2) + Unit + } + is E2eIdentityException.E2eiInvalidDomain -> { + buf.putInt(3) + Unit + } + is E2eIdentityException.CryptoException -> { + buf.putInt(4) + Unit + } + is E2eIdentityException.IdentityException -> { + buf.putInt(5) + Unit + } + is E2eIdentityException.UrlException -> { + buf.putInt(6) + Unit + } + is E2eIdentityException.JsonException -> { + buf.putInt(7) + Unit + } + is E2eIdentityException.Utf8Exception -> { + buf.putInt(8) + Unit + } + is E2eIdentityException.MlsException -> { + buf.putInt(9) + Unit + } + is E2eIdentityException.LockPoisonException -> { + buf.putInt(10) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } + +} + + + + +enum class E2eiConversationState { + VERIFIED,DEGRADED,NOT_ENABLED; +} + +public object FfiConverterTypeE2eiConversationState: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + E2eiConversationState.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: E2eiConversationState) = 4 + + override fun write(value: E2eiConversationState, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + +enum class MlsCredentialType { + BASIC,X509; +} + +public object FfiConverterTypeMlsCredentialType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + MlsCredentialType.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: MlsCredentialType) = 4 + + override fun write(value: MlsCredentialType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + +enum class MlsGroupInfoEncryptionType { + PLAINTEXT,JWE_ENCRYPTED; +} + +public object FfiConverterTypeMlsGroupInfoEncryptionType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + MlsGroupInfoEncryptionType.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: MlsGroupInfoEncryptionType) = 4 + + override fun write(value: MlsGroupInfoEncryptionType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + +enum class MlsRatchetTreeType { + FULL,DELTA,BY_REF; +} + +public object FfiConverterTypeMlsRatchetTreeType: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + MlsRatchetTreeType.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: MlsRatchetTreeType) = 4 + + override fun write(value: MlsRatchetTreeType, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + +enum class MlsWirePolicy { + PLAINTEXT,CIPHERTEXT; +} + +public object FfiConverterTypeMlsWirePolicy: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + MlsWirePolicy.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: MlsWirePolicy) = 4 + + override fun write(value: MlsWirePolicy, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + + + + + + +internal typealias Handle = Long +internal class ConcurrentHandleMap( + private val leftMap: MutableMap = mutableMapOf(), + private val rightMap: MutableMap = mutableMapOf() +) { + private val lock = java.util.concurrent.locks.ReentrantLock() + private val currentHandle = AtomicLong(0L) + private val stride = 1L + + fun insert(obj: T): Handle = + lock.withLock { + rightMap[obj] ?: + currentHandle.getAndAdd(stride) + .also { handle -> + leftMap[handle] = obj + rightMap[obj] = handle + } + } + + fun get(handle: Handle) = lock.withLock { + leftMap[handle] + } + + fun delete(handle: Handle) { + this.remove(handle) + } + + fun remove(handle: Handle): T? = + lock.withLock { + leftMap.remove(handle)?.let { obj -> + rightMap.remove(obj) + obj + } + } +} + +interface ForeignCallback : com.sun.jna.Callback { + public fun invoke(handle: Handle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int +} + +// Magic number for the Rust proxy to call using the same mechanism as every other method, +// to free the callback once it's dropped by Rust. +internal const val IDX_CALLBACK_FREE = 0 +// Callback return codes +internal const val UNIFFI_CALLBACK_SUCCESS = 0 +internal const val UNIFFI_CALLBACK_ERROR = 1 +internal const val UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 + +public abstract class FfiConverterCallbackInterface( + protected val foreignCallback: ForeignCallback +): FfiConverter { + private val handleMap = ConcurrentHandleMap() + + // Registers the foreign callback with the Rust side. + // This method is generated for each callback interface. + internal abstract fun register(lib: _UniFFILib) + + fun drop(handle: Handle): RustBuffer.ByValue { + return handleMap.remove(handle).let { RustBuffer.ByValue() } + } + + override fun lift(value: Handle): CallbackInterface { + return handleMap.get(value) ?: throw InternalException("No callback in handlemap; this is a Uniffi bug") + } + + override fun read(buf: ByteBuffer) = lift(buf.getLong()) + + override fun lower(value: CallbackInterface) = + handleMap.insert(value).also { + assert(handleMap.get(it) === value) { "Handle map is not returning the object we just placed there. This is a bug in the HandleMap." } + } + + override fun allocationSize(value: CallbackInterface) = 8 + + override fun write(value: CallbackInterface, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + +// Declaration and FfiConverters for CoreCryptoCallbacks Callback Interface + +public interface CoreCryptoCallbacks { + fun `authorize`(`conversationId`: ByteArray, `clientId`: ClientId): Boolean + fun `userAuthorize`(`conversationId`: ByteArray, `externalClientId`: ClientId, `existingClients`: List): Boolean + fun `clientIsExistingGroupUser`(`conversationId`: ByteArray, `clientId`: ClientId, `existingClients`: List, `parentConversationClients`: List?): Boolean + +} + +// The ForeignCallback that is passed to Rust. +internal class ForeignCallbackTypeCoreCryptoCallbacks : ForeignCallback { + @Suppress("TooGenericExceptionCaught") + override fun invoke(handle: Handle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val cb = FfiConverterTypeCoreCryptoCallbacks.lift(handle) + return when (method) { + IDX_CALLBACK_FREE -> { + FfiConverterTypeCoreCryptoCallbacks.drop(handle) + // Successful return + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + UNIFFI_CALLBACK_SUCCESS + } + 1 -> { + // Call the method, write to outBuf and return a status code + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for info + try { + this.`invokeAuthorize`(cb, argsData, argsLen, outBuf) + } catch (e: Throwable) { + // Unexpected error + try { + // Try to serialize the error into a string + outBuf.setValue(FfiConverterString.lower(e.toString())) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + 2 -> { + // Call the method, write to outBuf and return a status code + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for info + try { + this.`invokeUserAuthorize`(cb, argsData, argsLen, outBuf) + } catch (e: Throwable) { + // Unexpected error + try { + // Try to serialize the error into a string + outBuf.setValue(FfiConverterString.lower(e.toString())) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + 3 -> { + // Call the method, write to outBuf and return a status code + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for info + try { + this.`invokeClientIsExistingGroupUser`(cb, argsData, argsLen, outBuf) + } catch (e: Throwable) { + // Unexpected error + try { + // Try to serialize the error into a string + outBuf.setValue(FfiConverterString.lower(e.toString())) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + + else -> { + // An unexpected error happened. + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + try { + // Try to serialize the error into a string + outBuf.setValue(FfiConverterString.lower("Invalid Callback index")) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + } + + + @Suppress("UNUSED_PARAMETER") + private fun `invokeAuthorize`(kotlinCallbackInterface: CoreCryptoCallbacks, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val argsBuf = argsData.getByteBuffer(0, argsLen.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + fun makeCall() : Int { + val returnValue = kotlinCallbackInterface.`authorize`( + FfiConverterByteArray.read(argsBuf) + , + FfiConverterTypeClientId.read(argsBuf) + + ) + outBuf.setValue(FfiConverterBoolean.lowerIntoRustBuffer(returnValue)) + return UNIFFI_CALLBACK_SUCCESS + } + fun makeCallAndHandleError() : Int = makeCall() + + return makeCallAndHandleError() + } + + @Suppress("UNUSED_PARAMETER") + private fun `invokeUserAuthorize`(kotlinCallbackInterface: CoreCryptoCallbacks, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val argsBuf = argsData.getByteBuffer(0, argsLen.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + fun makeCall() : Int { + val returnValue = kotlinCallbackInterface.`userAuthorize`( + FfiConverterByteArray.read(argsBuf) + , + FfiConverterTypeClientId.read(argsBuf) + , + FfiConverterSequenceTypeClientId.read(argsBuf) + + ) + outBuf.setValue(FfiConverterBoolean.lowerIntoRustBuffer(returnValue)) + return UNIFFI_CALLBACK_SUCCESS + } + fun makeCallAndHandleError() : Int = makeCall() + + return makeCallAndHandleError() + } + + @Suppress("UNUSED_PARAMETER") + private fun `invokeClientIsExistingGroupUser`(kotlinCallbackInterface: CoreCryptoCallbacks, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val argsBuf = argsData.getByteBuffer(0, argsLen.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + fun makeCall() : Int { + val returnValue = kotlinCallbackInterface.`clientIsExistingGroupUser`( + FfiConverterByteArray.read(argsBuf) + , + FfiConverterTypeClientId.read(argsBuf) + , + FfiConverterSequenceTypeClientId.read(argsBuf) + , + FfiConverterOptionalSequenceTypeClientId.read(argsBuf) + + ) + outBuf.setValue(FfiConverterBoolean.lowerIntoRustBuffer(returnValue)) + return UNIFFI_CALLBACK_SUCCESS + } + fun makeCallAndHandleError() : Int = makeCall() + + return makeCallAndHandleError() + } + +} + +// The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. +public object FfiConverterTypeCoreCryptoCallbacks: FfiConverterCallbackInterface( + foreignCallback = ForeignCallbackTypeCoreCryptoCallbacks() +) { + override fun register(lib: _UniFFILib) { + rustCall() { status -> + lib.uniffi_CoreCrypto_fn_init_callback_corecryptocallbacks(this.foreignCallback, status) + } + } +} + + + + +public object FfiConverterOptionalULong: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ULong? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterULong.read(buf) + } + + override fun allocationSize(value: ULong?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterULong.allocationSize(value) + } + } + + override fun write(value: ULong?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterULong.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): String? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterString.read(buf) + } + + override fun allocationSize(value: String?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterString.allocationSize(value) + } + } + + override fun write(value: String?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterString.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalByteArray: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ByteArray? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterByteArray.read(buf) + } + + override fun allocationSize(value: ByteArray?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterByteArray.allocationSize(value) + } + } + + override fun write(value: ByteArray?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterByteArray.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalDuration: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): java.time.Duration? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterDuration.read(buf) + } + + override fun allocationSize(value: java.time.Duration?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterDuration.allocationSize(value) + } + } + + override fun write(value: java.time.Duration?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterDuration.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeAcmeChallenge: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): AcmeChallenge? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeAcmeChallenge.read(buf) + } + + override fun allocationSize(value: AcmeChallenge?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterTypeAcmeChallenge.allocationSize(value) + } + } + + override fun write(value: AcmeChallenge?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeAcmeChallenge.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeCommitBundle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CommitBundle? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeCommitBundle.read(buf) + } + + override fun allocationSize(value: CommitBundle?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterTypeCommitBundle.allocationSize(value) + } + } + + override fun write(value: CommitBundle?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeCommitBundle.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeWireIdentity: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): WireIdentity? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeWireIdentity.read(buf) + } + + override fun allocationSize(value: WireIdentity?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterTypeWireIdentity.allocationSize(value) + } + } + + override fun write(value: WireIdentity?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeWireIdentity.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeMlsWirePolicy: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): MlsWirePolicy? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeMlsWirePolicy.read(buf) + } + + override fun allocationSize(value: MlsWirePolicy?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterTypeMlsWirePolicy.allocationSize(value) + } + } + + override fun write(value: MlsWirePolicy?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeMlsWirePolicy.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalSequenceTypeDecryptedMessage: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceTypeDecryptedMessage.read(buf) + } + + override fun allocationSize(value: List?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterSequenceTypeDecryptedMessage.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceTypeDecryptedMessage.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalSequenceTypeClientId: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterSequenceTypeClientId.read(buf) + } + + override fun allocationSize(value: List?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterSequenceTypeClientId.allocationSize(value) + } + } + + override fun write(value: List?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterSequenceTypeClientId.write(value, buf) + } + } +} + + + + +public object FfiConverterOptionalTypeClientId: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ClientId? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeClientId.read(buf) + } + + override fun allocationSize(value: ClientId?): Int { + if (value == null) { + return 1 + } else { + return 1 + FfiConverterTypeClientId.allocationSize(value) + } + } + + override fun write(value: ClientId?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeClientId.write(value, buf) + } + } +} + + + + +public object FfiConverterSequenceUByte: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterUByte.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterUByte.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterUByte.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceUShort: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterUShort.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterUShort.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterUShort.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterString.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterString.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterString.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceByteArray: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterByteArray.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterByteArray.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterByteArray.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeCommitBundle: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeCommitBundle.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypeCommitBundle.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypeCommitBundle.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeDecryptedMessage: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeDecryptedMessage.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypeDecryptedMessage.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypeDecryptedMessage.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeInvitee: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeInvitee.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypeInvitee.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypeInvitee.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypePerDomainTrustAnchor: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypePerDomainTrustAnchor.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypePerDomainTrustAnchor.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypePerDomainTrustAnchor.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeProposalBundle: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeProposalBundle.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypeProposalBundle.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypeProposalBundle.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceSequenceUByte: FfiConverterRustBuffer>> { + override fun read(buf: ByteBuffer): List> { + val len = buf.getInt() + return List>(len) { + FfiConverterSequenceUByte.read(buf) + } + } + + override fun allocationSize(value: List>): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterSequenceUByte.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List>, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterSequenceUByte.write(it, buf) + } + } +} + + + + +public object FfiConverterSequenceTypeClientId: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeClientId.read(buf) + } + } + + override fun allocationSize(value: List): Int { + val sizeForLength = 4 + val sizeForItems = value.map { FfiConverterTypeClientId.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.forEach { + FfiConverterTypeClientId.write(it, buf) + } + } +} + + + +public object FfiConverterMapStringSequenceUByte: FfiConverterRustBuffer>> { + override fun read(buf: ByteBuffer): Map> { + // TODO: Once Kotlin's `buildMap` API is stabilized we should use it here. + val items : MutableMap> = mutableMapOf() + val len = buf.getInt() + repeat(len) { + val k = FfiConverterString.read(buf) + val v = FfiConverterSequenceUByte.read(buf) + items[k] = v + } + return items + } + + override fun allocationSize(value: Map>): Int { + val spaceForMapSize = 4 + val spaceForChildren = value.map { (k, v) -> + FfiConverterString.allocationSize(k) + + FfiConverterSequenceUByte.allocationSize(v) + }.sum() + return spaceForMapSize + spaceForChildren + } + + override fun write(value: Map>, buf: ByteBuffer) { + buf.putInt(value.size) + // The parens on `(k, v)` here ensure we're calling the right method, + // which is important for compatibility with older android devices. + // Ref https://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/ + value.forEach { (k, v) -> + FfiConverterString.write(k, buf) + FfiConverterSequenceUByte.write(v, buf) + } + } +} + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +public typealias Ciphersuite = UShort +public typealias FfiConverterTypeCiphersuite = FfiConverterUShort + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +public typealias Ciphersuites = List +public typealias FfiConverterTypeCiphersuites = FfiConverterSequenceUShort + + + +/** + * Typealias from the type name used in the UDL file to the builtin type. This + * is needed because the UDL type name is used in function/method signatures. + * It's also what we have an external type that references a custom type. + */ +public typealias ClientId = List +public typealias FfiConverterTypeClientId = FfiConverterSequenceUByte +// Async return type handlers + + + + + + + + + + + +// FFI type for callback handlers +internal interface UniFfiFutureCallbackByte : com.sun.jna.Callback { + // Note: callbackData is always 0. We could pass Rust a pointer/usize to represent the + // continuation, but with JNA it's easier to just store it in the callback handler. + fun invoke(_callbackData: USize, returnValue: Byte?, callStatus: RustCallStatus.ByValue); +} +internal interface UniFfiFutureCallbackShort : com.sun.jna.Callback { + // Note: callbackData is always 0. We could pass Rust a pointer/usize to represent the + // continuation, but with JNA it's easier to just store it in the callback handler. + fun invoke(_callbackData: USize, returnValue: Short?, callStatus: RustCallStatus.ByValue); +} +internal interface UniFfiFutureCallbackInt : com.sun.jna.Callback { + // Note: callbackData is always 0. We could pass Rust a pointer/usize to represent the + // continuation, but with JNA it's easier to just store it in the callback handler. + fun invoke(_callbackData: USize, returnValue: Int?, callStatus: RustCallStatus.ByValue); +} +internal interface UniFfiFutureCallbackLong : com.sun.jna.Callback { + // Note: callbackData is always 0. We could pass Rust a pointer/usize to represent the + // continuation, but with JNA it's easier to just store it in the callback handler. + fun invoke(_callbackData: USize, returnValue: Long?, callStatus: RustCallStatus.ByValue); +} +internal interface UniFfiFutureCallbackPointer : com.sun.jna.Callback { + // Note: callbackData is always 0. We could pass Rust a pointer/usize to represent the + // continuation, but with JNA it's easier to just store it in the callback handler. + fun invoke(_callbackData: USize, returnValue: Pointer?, callStatus: RustCallStatus.ByValue); +} +internal interface UniFfiFutureCallbackRustBuffer : com.sun.jna.Callback { + // Note: callbackData is always 0. We could pass Rust a pointer/usize to represent the + // continuation, but with JNA it's easier to just store it in the callback handler. + fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue); +} + +// Callback handlers for an async call. These are invoked by Rust when the future is ready. They +// lift the return value or error and resume the suspended function. + +internal class UniFfiFutureCallbackHandlerVoid_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackByte { + override fun invoke(_callbackData: USize, returnValue: Byte?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(Unit) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerVoid_TypeE2eIdentityError(val continuation: Continuation) + : UniFfiFutureCallbackByte { + override fun invoke(_callbackData: USize, returnValue: Byte?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(E2eIdentityException, callStatus) + continuation.resume(Unit) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerUShort_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackShort { + override fun invoke(_callbackData: USize, returnValue: Short?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterUShort.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerUInt(val continuation: Continuation) + : UniFfiFutureCallbackInt { + override fun invoke(_callbackData: USize, returnValue: Int?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(NullCallStatusErrorHandler, callStatus) + continuation.resume(FfiConverterUInt.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerULong_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackLong { + override fun invoke(_callbackData: USize, returnValue: Long?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterULong.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerBoolean(val continuation: Continuation) + : UniFfiFutureCallbackByte { + override fun invoke(_callbackData: USize, returnValue: Byte?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(NullCallStatusErrorHandler, callStatus) + continuation.resume(FfiConverterBoolean.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerBoolean_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackByte { + override fun invoke(_callbackData: USize, returnValue: Byte?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterBoolean.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerString(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(NullCallStatusErrorHandler, callStatus) + continuation.resume(FfiConverterString.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerString_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterString.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerString_TypeE2eIdentityError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(E2eIdentityException, callStatus) + continuation.resume(FfiConverterString.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeCoreCrypto_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackPointer { + override fun invoke(_callbackData: USize, returnValue: Pointer?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeCoreCrypto.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeWireE2eIdentity_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackPointer { + override fun invoke(_callbackData: USize, returnValue: Pointer?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeWireE2eIdentity.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeAcmeDirectory_TypeE2eIdentityError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(E2eIdentityException, callStatus) + continuation.resume(FfiConverterTypeAcmeDirectory.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeCommitBundle_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeCommitBundle.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeConversationInitBundle_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeConversationInitBundle.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeDecryptedMessage_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeDecryptedMessage.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeMemberAddedMessages_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeMemberAddedMessages.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeNewAcmeAuthz_TypeE2eIdentityError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(E2eIdentityException, callStatus) + continuation.resume(FfiConverterTypeNewAcmeAuthz.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeNewAcmeOrder_TypeE2eIdentityError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(E2eIdentityException, callStatus) + continuation.resume(FfiConverterTypeNewAcmeOrder.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeProposalBundle_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeProposalBundle.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeProteusAutoPrekeyBundle_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeProteusAutoPrekeyBundle.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeRotateBundle_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeRotateBundle.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerTypeE2eiConversationState_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterTypeE2eiConversationState.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerOptionalTypeCommitBundle_TypeCryptoError(val continuation: Continuation) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterOptionalTypeCommitBundle.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerOptionalSequenceTypeDecryptedMessage_TypeCryptoError(val continuation: Continuation?>) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterOptionalSequenceTypeDecryptedMessage.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerSequenceUByte_TypeCryptoError(val continuation: Continuation>) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterSequenceUByte.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerSequenceUByte_TypeE2eIdentityError(val continuation: Continuation>) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(E2eIdentityException, callStatus) + continuation.resume(FfiConverterSequenceUByte.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerSequenceSequenceUByte_TypeCryptoError(val continuation: Continuation>>) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterSequenceSequenceUByte.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerSequenceTypeClientId_TypeCryptoError(val continuation: Continuation>) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterSequenceTypeClientId.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +internal class UniFfiFutureCallbackHandlerMapStringSequenceUByte_TypeCryptoError(val continuation: Continuation>>) + : UniFfiFutureCallbackRustBuffer { + override fun invoke(_callbackData: USize, returnValue: RustBuffer.ByValue?, callStatus: RustCallStatus.ByValue) { + try { + checkCallStatus(CryptoException, callStatus) + continuation.resume(FfiConverterMapStringSequenceUByte.lift(returnValue!!)) + } catch (e: Throwable) { + continuation.resumeWithException(e) + } + } +} + +fun `version`(): String { + return FfiConverterString.lift( + rustCall() { _status -> + _UniFFILib.INSTANCE.uniffi_CoreCrypto_fn_func_version(_status) +}) +} + +@Throws(CryptoException::class) + +@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") +suspend fun `coreCryptoDeferredInit`(`path`: String, `key`: String, `ciphersuites`: Ciphersuites) : CoreCrypto { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeCoreCrypto_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeCoreCrypto_TypeCryptoError(continuation) + callbackHolder = callback + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_func_core_crypto_deferred_init( + FfiConverterString.lower(`path`),FfiConverterString.lower(`key`),FfiConverterTypeCiphersuites.lower(`ciphersuites`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } +} +@Throws(CryptoException::class) + +@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") +suspend fun `coreCryptoNew`(`path`: String, `key`: String, `clientId`: ClientId, `ciphersuites`: Ciphersuites) : CoreCrypto { + // Create a new `CoroutineScope` for this operation, suspend the coroutine, and call the + // scaffolding function, passing it one of the callback handlers from `AsyncTypes.kt`. + // + // Make sure to retain a reference to the callback handler to ensure that it's not GCed before + // it's invoked + var callbackHolder: UniFfiFutureCallbackHandlerTypeCoreCrypto_TypeCryptoError? = null + return coroutineScope { + val scope = this + return@coroutineScope suspendCoroutine { continuation -> + try { + val callback = UniFfiFutureCallbackHandlerTypeCoreCrypto_TypeCryptoError(continuation) + callbackHolder = callback + rustCall { status -> + _UniFFILib.INSTANCE.uniffi_core_crypto_ffi_fn_func_core_crypto_new( + FfiConverterString.lower(`path`),FfiConverterString.lower(`key`),FfiConverterTypeClientId.lower(`clientId`),FfiConverterTypeCiphersuites.lower(`ciphersuites`), + FfiConverterForeignExecutor.lower(scope), + callback, + USize(0), + status, + ) + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } +} + diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/CoreCryptoCentral.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/CoreCryptoCentral.kt new file mode 100644 index 0000000000..6ad7cdcb82 --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/CoreCryptoCentral.kt @@ -0,0 +1,100 @@ +package com.wire.crypto.client + +import com.wire.crypto.* +import java.io.File + +typealias EnrollmentHandle = ByteArray + +private class Callbacks : CoreCryptoCallbacks { + + override fun authorize(conversationId: ByteArray, clientId: List): Boolean = true + + override fun userAuthorize( + conversationId: ByteArray, + externalClientId: List, + existingClients: List> + ): Boolean = true + + override fun clientIsExistingGroupUser( + conversationId: ByteArray, + clientId: List, + existingClients: List>, + parentConversationClients: List>? + ): Boolean = true +} + +@Suppress("TooManyFunctions") +@OptIn(ExperimentalUnsignedTypes::class) +class CoreCryptoCentral private constructor(private val cc: CoreCrypto, private val rootDir: String) { + suspend fun proteusClient(): ProteusClient = ProteusClientImpl(cc, rootDir) + + suspend fun mlsClient(clientId: ClientId): MLSClient = MLSClient(cc).apply { mlsInit(clientId) } + + suspend fun e2eiNewEnrollment( + clientId: String, + displayName: String, + handle: String, + expiryDays: UInt, + ciphersuite: Ciphersuite, + ): E2EIClient { + return E2EIClient(cc.e2eiNewEnrollment(clientId, displayName, handle, expiryDays, ciphersuite.lower())) + } + + suspend fun e2eiNewActivationEnrollment( + clientId: String, + displayName: String, + handle: String, + expiryDays: UInt, + ciphersuite: Ciphersuite, + ): E2EIClient { + return E2EIClient( + cc.e2eiNewActivationEnrollment( + clientId, + displayName, + handle, + expiryDays, + ciphersuite.lower() + ) + ) + } + + suspend fun e2eiNewRotateEnrollment( + clientId: String, + expiryDays: UInt, + ciphersuite: Ciphersuite, + displayName: String? = null, + handle: String? = null, + ): E2EIClient { + return E2EIClient(cc.e2eiNewRotateEnrollment(clientId, displayName, handle, expiryDays, ciphersuite.lower())) + } + + suspend fun e2eiMlsInitOnly(enrollment: E2EIClient, certificateChain: String): MLSClient { + cc.e2eiMlsInitOnly(enrollment.delegate, certificateChain) + return MLSClient(cc) + } + + suspend fun e2eiEnrollmentStash(enrollment: E2EIClient): EnrollmentHandle { + return cc.e2eiEnrollmentStash(enrollment.delegate).toUByteArray().asByteArray() + } + + suspend fun e2eiEnrollmentStashPop(handle: EnrollmentHandle): E2EIClient { + return E2EIClient(cc.e2eiEnrollmentStashPop(handle.asUByteArray().asList())) + } + + companion object { + private const val KEYSTORE_NAME = "keystore" + fun CiphersuiteName.lower() = (ordinal + 1).toUShort() + val DEFAULT_CREDENTIAL_TYPE = MlsCredentialType.BASIC + val DEFAULT_CIPHERSUITE = CiphersuiteName.MLS_128_DHKEMX25519_AES128GCM_SHA256_ED25519.lower() + val DEFAULT_CIPHERSUITES = listOf(DEFAULT_CIPHERSUITE) + + suspend operator fun invoke(rootDir: String, databaseKey: String): CoreCryptoCentral { + val path = "$rootDir/$KEYSTORE_NAME" + File(rootDir).mkdirs() + val cc = coreCryptoDeferredInit(path, databaseKey, DEFAULT_CIPHERSUITES) + cc.setCallbacks(Callbacks()) + return CoreCryptoCentral(cc, rootDir) + } + } +} + diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/E2EIModel.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/E2EIModel.kt new file mode 100644 index 0000000000..57a1d27c9c --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/E2EIModel.kt @@ -0,0 +1,2 @@ +package com.wire.crypto.client + diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/E2eiClient.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/E2eiClient.kt new file mode 100644 index 0000000000..98c0c1875d --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/E2eiClient.kt @@ -0,0 +1,127 @@ +package com.wire.crypto.client + +import com.wire.crypto.WireE2eIdentity +import com.wire.crypto.client.AcmeChallenge.Companion.toAcmeChallenge +import com.wire.crypto.client.AcmeDirectory.Companion.toAcmeDirectory +import com.wire.crypto.client.NewAcmeAuthz.Companion.toNewAcmeAuthz +import com.wire.crypto.client.NewAcmeOrder.Companion.toNewAcmeOrder + +typealias JsonRawData = ByteArray +typealias DpopToken = String + +data class AcmeDirectory( + val newNonce: String, + val newAccount: String, + val newOrder: String +) { + constructor(delegate: com.wire.crypto.AcmeDirectory) : this( + delegate.newNonce, + delegate.newAccount, + delegate.newOrder + ) + + companion object { + fun com.wire.crypto.AcmeDirectory.toAcmeDirectory() = AcmeDirectory(this) + } +} + +data class NewAcmeOrder(val delegate: JsonRawData, val authorizations: List) { + + @OptIn(ExperimentalUnsignedTypes::class) + constructor(delegate: com.wire.crypto.NewAcmeOrder) : this( + delegate.delegate.toUByteArray().asByteArray(), + delegate.authorizations, + ) + + companion object { + fun com.wire.crypto.NewAcmeOrder.toNewAcmeOrder() = NewAcmeOrder(this) + } +} + +data class AcmeChallenge(val delegate: JsonRawData, val url: String) { + @OptIn(ExperimentalUnsignedTypes::class) + constructor(delegate: com.wire.crypto.AcmeChallenge) : this( + delegate.delegate.toUByteArray().asByteArray(), delegate.url + ) + + companion object { + fun com.wire.crypto.AcmeChallenge.toAcmeChallenge() = AcmeChallenge(this) + } +} + +data class NewAcmeAuthz( + val identifier: String, + val wireOidcChallenge: AcmeChallenge?, + val wireDpopChallenge: AcmeChallenge? +) { + constructor(delegate: com.wire.crypto.NewAcmeAuthz) : this( + delegate.identifier, + delegate.wireOidcChallenge?.toAcmeChallenge(), + delegate.wireDpopChallenge?.toAcmeChallenge(), + ) + + companion object { + fun com.wire.crypto.NewAcmeAuthz.toNewAcmeAuthz() = NewAcmeAuthz(this) + } +} + +@Suppress("TooManyFunctions") +@OptIn(ExperimentalUnsignedTypes::class) +class E2EIClient(val delegate: WireE2eIdentity) { + + private val defaultDPoPTokenExpiry: UInt = 30U + + suspend fun directoryResponse(directory: JsonRawData) = + delegate.directoryResponse(directory.toUByteList()).toAcmeDirectory() + + suspend fun newAccountRequest(previousNonce: String) = + delegate.newAccountRequest(previousNonce).toByteArray() + + suspend fun accountResponse(account: JsonRawData) = + delegate.newAccountResponse(account.toUByteList()) + + suspend fun newOrderRequest(previousNonce: String) = + delegate.newOrderRequest(previousNonce).toByteArray() + + suspend fun newOrderResponse(order: JsonRawData) = + delegate.newOrderResponse(order.toUByteList()).toNewAcmeOrder() + + suspend fun newAuthzRequest(url: String, previousNonce: String) = + delegate.newAuthzRequest(url, previousNonce).toByteArray() + + suspend fun authzResponse(authz: JsonRawData) = + delegate.newAuthzResponse(authz.toUByteList()).toNewAcmeAuthz() + + suspend fun createDpopToken(backendNonce: String) = + delegate.createDpopToken(expirySecs = defaultDPoPTokenExpiry, backendNonce) + + suspend fun newDpopChallengeRequest(accessToken: String, previousNonce: String) = + delegate.newDpopChallengeRequest(accessToken, previousNonce).toByteArray() + + suspend fun newOidcChallengeRequest(idToken: String, previousNonce: String) = + delegate.newOidcChallengeRequest(idToken, previousNonce).toByteArray() + + suspend fun challengeResponse(challenge: JsonRawData) = + delegate.newChallengeResponse(challenge.toUByteList()) + + suspend fun checkOrderRequest(orderUrl: String, previousNonce: String) = + delegate.checkOrderRequest(orderUrl, previousNonce).toByteArray() + + suspend fun checkOrderResponse(order: JsonRawData) = + delegate.checkOrderResponse(order.toUByteList()) + + suspend fun finalizeRequest(previousNonce: String) = + delegate.finalizeRequest(previousNonce).toByteArray() + + suspend fun finalizeResponse(finalize: JsonRawData) = + delegate.finalizeResponse(finalize.toUByteList()) + + suspend fun certificateRequest(previousNonce: String) = + delegate.certificateRequest(previousNonce).toByteArray() + + companion object { + + fun ByteArray.toUByteList(): List = map { it.toUByte() } + fun List.toByteArray() = toUByteArray().asByteArray() + } +} diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/MLSClient.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/MLSClient.kt new file mode 100644 index 0000000000..2a03ca6915 --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/MLSClient.kt @@ -0,0 +1,161 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +package com.wire.crypto.client + +import com.wire.crypto.client.CoreCryptoCentral.Companion.DEFAULT_CIPHERSUITE +import com.wire.crypto.client.CoreCryptoCentral.Companion.DEFAULT_CIPHERSUITES +import kotlin.time.Duration +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +@Suppress("TooManyFunctions") +@OptIn(ExperimentalUnsignedTypes::class) +class MLSClient(private val cc: com.wire.crypto.CoreCrypto) { + + companion object { + + private val keyRotationDuration: Duration = 30.toDuration(DurationUnit.DAYS) + private val defaultGroupConfiguration = + com.wire.crypto.CustomConfiguration( + java.time.Duration.ofDays(keyRotationDuration.inWholeDays), + com.wire.crypto.MlsWirePolicy.PLAINTEXT + ) + + } + + suspend fun mlsInit(id: ClientId) { + cc.mlsInit(id.lower(), DEFAULT_CIPHERSUITES) + } + + suspend fun getPublicKey(ciphersuite: Ciphersuite): SignaturePublicKey { + return cc.clientPublicKey(ciphersuite.lower()).toSignaturePublicKey() + } + + suspend fun generateKeyPackages( + ciphersuite: Ciphersuite, + credentialType: CredentialType, + amount: UInt + ): List { + return cc.clientKeypackages(ciphersuite.lower(), credentialType.lower(), amount) + .map { it.toMLSKeyPackage() } + } + + suspend fun validKeyPackageCount(ciphersuite: Ciphersuite, credentialType: CredentialType): ULong { + return cc.clientValidKeypackagesCount(ciphersuite.lower(), credentialType.lower()) + } + + suspend fun updateKeyingMaterial(id: MLSGroupId) = CommitBundle(cc.updateKeyingMaterial(id.lower())) + + suspend fun conversationExists(id: MLSGroupId): Boolean = cc.conversationExists(id.lower()) + + suspend fun conversationEpoch(id: MLSGroupId): ULong = cc.conversationEpoch(id.lower()) + + suspend fun joinConversation( + id: MLSGroupId, + epoch: ULong, + ciphersuite: Ciphersuite, + credentialType: CredentialType, + ): MlsMessage { + return cc.newExternalAddProposal(id.lower(), epoch, ciphersuite.lower(), credentialType.lower()).toMlsMessage() + } + + suspend fun joinByExternalCommit(groupInfo: GroupInfo, credentialType: CredentialType): CommitBundle { + return CommitBundle( + cc.joinByExternalCommit( + groupInfo.lower(), + defaultGroupConfiguration, + credentialType.lower() + ) + ) + } + + suspend fun mergePendingGroupFromExternalCommit(id: MLSGroupId): List? { + return cc.mergePendingGroupFromExternalCommit(id.lower())?.map { DecryptedMessage(it) } + } + + suspend fun clearPendingGroupExternalCommit(id: MLSGroupId) = cc.clearPendingGroupFromExternalCommit(id.lower()) + + suspend fun createConversation( + id: MLSGroupId, + creatorCredentialType: CredentialType, + externalSenders: List = emptyList(), + perDomainTrustAnchors: List = emptyList(), + ) { + val cfg = com.wire.crypto.ConversationConfiguration( + DEFAULT_CIPHERSUITE, + externalSenders.map { it.lower() }, + defaultGroupConfiguration, + perDomainTrustAnchors + ) + + cc.createConversation(id.lower(), creatorCredentialType.lower(), cfg) + } + + suspend fun wipeConversation(id: MLSGroupId) = cc.wipeConversation(id.lower()) + + suspend fun processWelcomeMessage(welcome: Welcome): MLSGroupId { + return cc.processWelcomeMessage(welcome.lower(), defaultGroupConfiguration).toGroupId() + } + + suspend fun encryptMessage(id: MLSGroupId, message: PlaintextMessage): MlsMessage { + return cc.encryptMessage(id.lower(), message.lower()).toMlsMessage() + } + + suspend fun updateTrustAnchorsFromConversation( + id: MLSGroupId, + removeDomainNames: List, + addTrustAnchors: List, + ): CommitBundle { + return CommitBundle( + cc.updateTrustAnchorsFromConversation(id.lower(), removeDomainNames, addTrustAnchors) + ) + } + + suspend fun decryptMessage(id: MLSGroupId, message: MlsMessage): DecryptedMessage { + return DecryptedMessage(cc.decryptMessage(id.lower(), message.lower())) + } + + suspend fun commitAccepted(id: MLSGroupId) = cc.commitAccepted(id.lower()) + + suspend fun commitPendingProposals(id: MLSGroupId) = cc.commitPendingProposals(id.lower())?.let { CommitBundle(it) } + + suspend fun clearPendingCommit(id: MLSGroupId) = cc.clearPendingCommit(id.lower()) + + suspend fun members(id: MLSGroupId): List = cc.getClientIds(id.lower()).map { it.toClientId() } + + suspend fun addMember(id: MLSGroupId, members: Map): CommitBundle { + val invitees = members.map { (clientId, kp) -> com.wire.crypto.Invitee(clientId.lower(), kp.lower()) } + return CommitBundle(cc.addClientsToConversation(id.lower(), invitees)) + } + + suspend fun removeMember(id: MLSGroupId, members: List): CommitBundle { + val clientIds = members.map { it.lower() } + return CommitBundle(cc.removeClientsFromConversation(id.lower(), clientIds)) + } + + suspend fun deriveSecret(id: MLSGroupId, keyLength: UInt): AvsSecret { + return cc.exportSecretKey(id.lower(), keyLength).toAvsSecret() + } + + suspend fun e2eiConversationState(id: MLSGroupId): com.wire.crypto.E2eiConversationState { + return cc.e2eiConversationState(id.lower()) + } + + suspend fun e2eiIsEnabled(ciphersuite: Ciphersuite): Boolean = cc.e2eiIsEnabled(ciphersuite.lower()) +} diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/MlsModel.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/MlsModel.kt new file mode 100644 index 0000000000..93794cd74d --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/MlsModel.kt @@ -0,0 +1,213 @@ +package com.wire.crypto.client + +import com.wire.crypto.MlsGroupInfoEncryptionType +import com.wire.crypto.MlsRatchetTreeType +import com.wire.crypto.ProposalBundle + +enum class Ciphersuite { + // DH KEM x25519 | AES-GCM 128 | SHA2-256 | Ed25519 + MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519, + + // DH KEM P256 | AES-GCM 128 | SHA2-256 | EcDSA P256 + MLS_128_DHKEMP256_AES128GCM_SHA256_P256, + + // DH KEM x25519 | Chacha20Poly1305 | SHA2-256 | Ed25519 + MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519, + + // DH KEM x448 | AES-GCM 256 | SHA2-512 | Ed448 + MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448, + + // DH KEM P521 | AES-GCM 256 | SHA2-512 | EcDSA P521 + MLS_256_DHKEMP521_AES256GCM_SHA512_P521, + + // DH KEM x448 | Chacha20Poly1305 | SHA2-512 | Ed448 + MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448, + + // DH KEM P384 | AES-GCM 256 | SHA2-384 | EcDSA P384 + MLS_256_DHKEMP384_AES256GCM_SHA384_P384, + + // x25519Kyber768Draft00 Hybrid KEM | AES-GCM 128 | SHA2-256 | Ed25519 + MLS_128_X25519KYBER768DRAFT00_AES128GCM_SHA256_Ed25519; + + fun lower() = (ordinal + 1).toUShort() +} + +enum class CredentialType { + Basic, + X509; + + fun lower() = when (this) { + Basic -> com.wire.crypto.MlsCredentialType.BASIC + X509 -> com.wire.crypto.MlsCredentialType.X509 + } +} + +interface FfiType { + val value: K + fun lower(): R +} + +interface Uniffi023 : FfiType> { + override fun lower() = value.map { it.toUByte() } +} + +interface Uniffi : FfiType { + override fun lower() = value +} + +@JvmInline +value class MLSGroupId(override val value: ByteArray) : Uniffi023 +@OptIn(ExperimentalUnsignedTypes::class) +fun List.toGroupId() = MLSGroupId(toUByteArray().asByteArray()) +fun String.toGroupId() = MLSGroupId(encodeToByteArray()) + +@JvmInline +@OptIn(ExperimentalUnsignedTypes::class) +value class ClientId(override val value: String) : FfiType { + + override fun lower() = value.encodeToByteArray().asUByteArray().asList() +} + +@OptIn(ExperimentalUnsignedTypes::class) +fun com.wire.crypto.ClientId.toClientId() = ClientId(String(toUByteArray().asByteArray())) +fun String.toClientId() = ClientId(this) + +@JvmInline +value class ExternalSenderKey(override val value: ByteArray) : Uniffi + +@JvmInline +value class Welcome(override val value: ByteArray) : Uniffi023 + +@JvmInline +value class MlsMessage(override val value: ByteArray) : Uniffi023 + +@OptIn(ExperimentalUnsignedTypes::class) +fun List.toMlsMessage() = MlsMessage(toUByteArray().asByteArray()) + +@JvmInline +value class AvsSecret(override val value: ByteArray) : Uniffi023 + +@OptIn(ExperimentalUnsignedTypes::class) +fun List.toAvsSecret() = AvsSecret(toUByteArray().asByteArray()) + +@JvmInline +value class PlaintextMessage(override val value: ByteArray) : Uniffi023 + +fun String.toPlaintextMessage() = PlaintextMessage(encodeToByteArray()) + +@JvmInline +value class SignaturePublicKey(override val value: ByteArray) : Uniffi023 + +@OptIn(ExperimentalUnsignedTypes::class) +fun List.toSignaturePublicKey() = SignaturePublicKey(toUByteArray().asByteArray()) + +@JvmInline +value class MLSKeyPackage(override val value: ByteArray) : Uniffi + +@OptIn(ExperimentalUnsignedTypes::class) +fun List.toMLSKeyPackage() = MLSKeyPackage(toUByteArray().asByteArray()) + +@JvmInline +value class GroupInfo(override val value: ByteArray) : Uniffi023 + +data class GroupInfoBundle( + val encryptionType: MlsGroupInfoEncryptionType, + val ratchetTreeType: MlsRatchetTreeType, + val payload: GroupInfo, +) { + constructor(delegate: com.wire.crypto.GroupInfoBundle) : this( + delegate.encryptionType, + delegate.ratchetTreeType, + GroupInfo(delegate.payload) + ) +} + +data class CommitBundle( + val commit: MlsMessage, + val welcome: Welcome?, + val groupInfoBundle: GroupInfoBundle, +) { + + constructor(delegate: com.wire.crypto.CommitBundle) : this( + MlsMessage(delegate.commit), + delegate.welcome?.let { Welcome(it) }, + GroupInfoBundle(delegate.groupInfo) + ) + + constructor(cib: com.wire.crypto.ConversationInitBundle) : this( + MlsMessage(cib.commit), + welcome = null, + GroupInfoBundle(cib.groupInfo) + ) + + constructor(mam: com.wire.crypto.MemberAddedMessages) : this( + MlsMessage(mam.commit), + Welcome(mam.welcome), + GroupInfoBundle(mam.groupInfo) + ) +} + +data class DecryptedMessage( + val message: ByteArray?, + val proposals: Set, + val isActive: Boolean, + val commitDelay: Long?, + val senderClientId: ClientId?, + val hasEpochChanged: Boolean, + val identity: WireIdentity?, +) { + constructor(delegate: com.wire.crypto.DecryptedMessage) : this( + delegate.message, + delegate.proposals.toSet(), + delegate.isActive, + delegate.commitDelay?.toLong(), + delegate.senderClientId?.toClientId(), + delegate.hasEpochChanged, + delegate.identity?.let { WireIdentity(it) } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as DecryptedMessage + + if (message != null) { + if (other.message == null) return false + if (!message.contentEquals(other.message)) return false + } else if (other.message != null) return false + if (proposals != other.proposals) return false + if (isActive != other.isActive) return false + if (commitDelay != other.commitDelay) return false + if (senderClientId != other.senderClientId) return false + if (hasEpochChanged != other.hasEpochChanged) return false + if (identity != other.identity) return false + + return true + } + + override fun hashCode(): Int { + var result = message?.contentHashCode() ?: 0 + result = 31 * result + proposals.hashCode() + result = 31 * result + isActive.hashCode() + result = 31 * result + (commitDelay?.hashCode() ?: 0) + result = 31 * result + (senderClientId?.hashCode() ?: 0) + result = 31 * result + hasEpochChanged.hashCode() + result = 31 * result + (identity?.hashCode() ?: 0) + return result + } +} + +data class WireIdentity( + val clientId: String, + val handle: String, + val displayName: String, + val domain: String +) { + constructor(delegate: com.wire.crypto.WireIdentity) : this( + delegate.clientId, + delegate.handle, + delegate.displayName, + delegate.domain, + ) +} diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/ProteusClient.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/ProteusClient.kt new file mode 100644 index 0000000000..8881ddc357 --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/ProteusClient.kt @@ -0,0 +1,221 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +package com.wire.crypto.client + +import com.wire.crypto.CoreCrypto +import com.wire.crypto.CryptoException +import java.io.File + +typealias SessionId = String + +data class PreKey( + val id: UShort, + val data: ByteArray +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as PreKey + + if (id != other.id) return false + if (!data.contentEquals(other.data)) return false + + return true + } + + override fun hashCode(): Int { + var result = id.hashCode() + result = 31 * result + data.contentHashCode() + return result + } +} + +interface ProteusClient { + + suspend fun getIdentity(): ByteArray + + suspend fun getLocalFingerprint(): ByteArray + + suspend fun getRemoteFingerprint(sessionId: SessionId): ByteArray + + suspend fun newPreKeys(from: Int, count: Int): ArrayList + + suspend fun newLastPreKey(): PreKey + + suspend fun doesSessionExist(sessionId: SessionId): Boolean + + suspend fun createSession(preKeyCrypto: PreKey, sessionId: SessionId) + + suspend fun deleteSession(sessionId: SessionId) + + suspend fun decrypt(message: ByteArray, sessionId: SessionId): ByteArray + + suspend fun encrypt(message: ByteArray, sessionId: SessionId): ByteArray + + suspend fun encryptBatched(message: ByteArray, sessionIds: List): Map + + suspend fun encryptWithPreKey( + message: ByteArray, + preKey: PreKey, + sessionId: SessionId + ): ByteArray +} + +@Suppress("TooManyFunctions") +class ProteusClientImpl private constructor(private val coreCrypto: CoreCrypto): ProteusClient { + override suspend fun getIdentity(): ByteArray { + return ByteArray(0) + } + + override suspend fun getLocalFingerprint(): ByteArray { + return wrapException { coreCrypto.proteusFingerprint().toByteArray() } + } + + override suspend fun getRemoteFingerprint(sessionId: SessionId): ByteArray { + return wrapException { coreCrypto.proteusFingerprintRemote(sessionId).toByteArray() } + } + + override suspend fun newPreKeys(from: Int, count: Int): ArrayList { + return wrapException { + from.until(from + count).map { + toPreKey(it.toUShort(), toByteArray(coreCrypto.proteusNewPrekey(it.toUShort()))) + } as ArrayList + } + } + + override suspend fun newLastPreKey(): PreKey { + return wrapException { toPreKey(coreCrypto.proteusLastResortPrekeyId(), toByteArray(coreCrypto.proteusLastResortPrekey())) } + } + + override suspend fun doesSessionExist(sessionId: SessionId): Boolean { + return wrapException { + coreCrypto.proteusSessionExists(sessionId) + } + } + + override suspend fun createSession(preKeyCrypto: PreKey, sessionId: SessionId) { + wrapException { coreCrypto.proteusSessionFromPrekey(sessionId, toUByteList(preKeyCrypto.data)) } + } + + override suspend fun deleteSession(sessionId: SessionId) { + wrapException { + coreCrypto.proteusSessionDelete(sessionId) + } + } + + override suspend fun decrypt(message: ByteArray, sessionId: SessionId): ByteArray { + val sessionExists = doesSessionExist(sessionId) + + return wrapException { + if (sessionExists) { + val decryptedMessage = toByteArray(coreCrypto.proteusDecrypt(sessionId, toUByteList(message))) + coreCrypto.proteusSessionSave(sessionId) + decryptedMessage + } else { + val decryptedMessage = toByteArray(coreCrypto.proteusSessionFromMessage(sessionId, toUByteList(message))) + coreCrypto.proteusSessionSave(sessionId) + decryptedMessage + } + } + } + + override suspend fun encrypt(message: ByteArray, sessionId: SessionId): ByteArray { + return wrapException { + val encryptedMessage = toByteArray(coreCrypto.proteusEncrypt(sessionId, toUByteList(message))) + coreCrypto.proteusSessionSave(sessionId) + encryptedMessage + } + } + + override suspend fun encryptBatched(message: ByteArray, sessionIds: List): Map { + return wrapException { + coreCrypto.proteusEncryptBatched(sessionIds.map { it }, toUByteList((message))).mapNotNull { entry -> + entry.key to toByteArray(entry.value) + } + }.toMap() + } + + override suspend fun encryptWithPreKey( + message: ByteArray, + preKey: PreKey, + sessionId: SessionId + ): ByteArray { + return wrapException { + coreCrypto.proteusSessionFromPrekey(sessionId, toUByteList(preKey.data)) + val encryptedMessage = toByteArray(coreCrypto.proteusEncrypt(sessionId, toUByteList(message))) + coreCrypto.proteusSessionSave(sessionId) + encryptedMessage + } + } + + @Suppress("TooGenericExceptionCaught") + private suspend fun wrapException(b: suspend () -> T): T { + try { + return b() + } catch (e: CryptoException) { + throw ProteusException(e.message, ProteusException.fromProteusCode(coreCrypto.proteusLastErrorCode().toInt()), e.cause) + } catch (e: Exception) { + throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause) + } + } + + @OptIn(ExperimentalUnsignedTypes::class) + companion object { + private fun toUByteList(value: ByteArray): List = value.asUByteArray().asList() + private fun toByteArray(value: List) = value.toUByteArray().asByteArray() + private fun toPreKey(id: UShort, data: ByteArray): PreKey = + PreKey(id, data) + + public fun needsMigration(rootDir: File): Boolean { + return cryptoBoxFilesExists(rootDir) + } + + private fun cryptoBoxFilesExists(rootDir: File): Boolean = + CRYPTO_BOX_FILES.any { + rootDir.resolve(it).exists() + } + + private val CRYPTO_BOX_FILES = listOf("identities", "prekeys", "sessions", "version") + + private fun deleteCryptoBoxFiles(rootDir: String): Boolean = + CRYPTO_BOX_FILES.fold(true) { acc, file -> + acc && File(rootDir).resolve(file).deleteRecursively() + } + + private suspend fun migrateFromCryptoBoxIfNecessary(coreCrypto: CoreCrypto, rootDir: String) { + if (cryptoBoxFilesExists(File(rootDir))) { + coreCrypto.proteusCryptoboxMigrate(rootDir) + deleteCryptoBoxFiles(rootDir) + } + } + + suspend operator fun invoke(coreCrypto: CoreCrypto, rootDir: String): ProteusClientImpl { + try { + migrateFromCryptoBoxIfNecessary(coreCrypto, rootDir) + coreCrypto.proteusInit() + return ProteusClientImpl(coreCrypto) + } catch (e: CryptoException) { + throw ProteusException(e.message, ProteusException.fromProteusCode(coreCrypto.proteusLastErrorCode().toInt()), e.cause) + } catch (e: Exception) { + throw ProteusException(e.message, ProteusException.Code.UNKNOWN_ERROR, e.cause) + } + } + } +} diff --git a/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/ProteusException.kt b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/ProteusException.kt new file mode 100644 index 0000000000..c1b127446b --- /dev/null +++ b/crypto-ffi/bindings/android/src/main/kotlin/com/wire/crypto/client/ProteusException.kt @@ -0,0 +1,193 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +package com.wire.crypto.client + +class ProteusException(message: String?, val code: Code, cause: Throwable? = null) : Exception(message, cause) { + + constructor(message: String?, code: Int, cause: Throwable? = null) : this(message, fromNativeCode(code), cause) + + enum class Code { + /** + * A requested session was not found. + */ + SESSION_NOT_FOUND, + + /** + * The remote identity of a session changed. + * + * + * Usually the user should be informed and the session reinitialised. + * If the remote fingerprint was previously verified, it will need to be + * verified anew in order to exclude any potential MITM. + */ + REMOTE_IDENTITY_CHANGED, + + /** + * The signature of a decrypted message is invalid. + * + * + * The message being decrypted is incomplete or has otherwise been + * tampered with. + */ + INVALID_SIGNATURE, + + /** + * A message is invalid. + * + * + * The message is well-formed but cannot be decrypted, e.g. + * because the message is used to initialise a session but does not + * contain a [PreKey] or the used session does not contain the + * appropriate key material for decrypting the message. The problem + * should be reported to the user, as it might be necessary for both + * peers to re-initialise their sessions. + */ + INVALID_MESSAGE, + + /** + * A message is a duplicate. + * + * + * The message being decrypted is a duplicate of a message that has + * previously been decrypted with the same session. The message can + * be safely discarded. + */ + DUPLICATE_MESSAGE, + + /** + * A message is too recent. + * + * + * There is an unreasonably large gap between the last decrypted + * message and the message being decrypted, i.e. there are too many + * intermediate messages missing. The message should be dropped. + */ + TOO_DISTANT_FUTURE, + + /** + * A message is too old. + * + * + * The message being decrypted is unreasonably old and cannot + * be decrypted any longer due to the key material no longer being available. + * The message should be dropped. + */ + OUTDATED_MESSAGE, + + /** + * A message or key could not be decoded. + * + * + * The message or key being decoded is either malformed or + * otherwise encoded in a way such it cannot be understood. + */ + DECODE_ERROR, + + /** + * An internal storage error occurred. + * + * + * An error occurred while loading or persisting key material. + * The operation may be retried a limited number of times. + */ + STORAGE_ERROR, + + /** + * A CBox has been opened with an incomplete or mismatching identity + * using [CryptoBox.openWith]. + * + * + * This is typically a programmer error. + */ + IDENTITY_ERROR, + + /** + * An attempt was made to initialise a new session using [CryptoBox.initSessionFromMessage] + * whereby the prekey corresponding to the prekey ID in the message could not be found. + */ + PREKEY_NOT_FOUND, + + /** + * A panic occurred. This is a last resort error raised form native code to + * signal a severe problem, like a violation of a critical invariant, that + * would otherwise have caused a crash. Client code can choose to handle + * these errors more gracefully, preventing the application from crashing. + * + * + * Note that any [CryptoSession]s which might have been involved in a + * computation leading to a panic must no longer be used as their in-memory + * state may be corrupt. Such sessions should be closed and may be subsequently + * reloaded to retry the operation(s). + */ + PANIC, + + /** + * An unspecified error occurred. + */ + UNKNOWN_ERROR, + + /** + * Local files were not found. + */ + LOCAL_FILES_NOT_FOUND; + } + + companion object { + @Suppress("MagicNumber") + fun fromNativeCode(code: Int): Code { + return when (code) { + 1 -> Code.STORAGE_ERROR + 2 -> Code.SESSION_NOT_FOUND + 3 -> Code.DECODE_ERROR + 4 -> Code.REMOTE_IDENTITY_CHANGED + 5 -> Code.INVALID_SIGNATURE + 6 -> Code.INVALID_MESSAGE + 7 -> Code.DUPLICATE_MESSAGE + 8 -> Code.TOO_DISTANT_FUTURE + 9 -> Code.OUTDATED_MESSAGE + 13 -> Code.IDENTITY_ERROR + 14 -> Code.PREKEY_NOT_FOUND + 15 -> Code.PANIC + else -> Code.UNKNOWN_ERROR + } + } + + // Mapping source: + // https://github.com/wireapp/proteus/blob/2.x/crates/proteus-traits/src/lib.rs + // https://github.com/wireapp/wire-web-core/blob/7383e108f5e9d15d0b82c41ed504964667463cfc/packages/proteus/README.md + fun fromProteusCode(code: Int): Code { + @Suppress("MagicNumber") + return when (code) { + 501 -> Code.STORAGE_ERROR + 102 -> Code.SESSION_NOT_FOUND + 3, 301, 302, 303 -> Code.DECODE_ERROR + 204 -> Code.REMOTE_IDENTITY_CHANGED + 206, 207, 210 -> Code.INVALID_SIGNATURE + 200, 201, 202, 205, 213 -> Code.INVALID_MESSAGE + 209 -> Code.DUPLICATE_MESSAGE + 211, 212 -> Code.TOO_DISTANT_FUTURE + 208 -> Code.OUTDATED_MESSAGE + 300 -> Code.IDENTITY_ERROR + 101 -> Code.PREKEY_NOT_FOUND + 5 -> Code.PANIC + else -> Code.UNKNOWN_ERROR + } + } + } +} diff --git a/crypto-ffi/bindings/android/src/test/kotlin/com/wire/crypto/client/MLSClientTest.kt b/crypto-ffi/bindings/android/src/test/kotlin/com/wire/crypto/client/MLSClientTest.kt new file mode 100644 index 0000000000..bd9987d617 --- /dev/null +++ b/crypto-ffi/bindings/android/src/test/kotlin/com/wire/crypto/client/MLSClientTest.kt @@ -0,0 +1,348 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +package com.wire.crypto.client + +import com.wire.crypto.E2eiConversationState +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import java.nio.file.Files +import kotlin.test.Test + +@OptIn(ExperimentalCoroutinesApi::class) +internal class MLSClientTest { + + companion object { + private val id = "JfflcPtUivbg+1U3Iyrzsh5D2ui/OGS5Rvf52ipH5KY=".toGroupId() + private val aliceId = "alice1" + private val aliceId2 = "alice2" + private val bobId = "bob" + private val carolId = "carol" + val defaultCiphersuite = Ciphersuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + val defaultCredentialType = CredentialType.Basic + } + + private fun newClients(vararg clientIds: String) = runBlocking { + clientIds.map { + val clientId = it.toClientId() + val root = Files.createTempDirectory("mls").toFile() + val keyStore = root.resolve("keystore-${clientId}") + CoreCryptoCentral(keyStore.absolutePath, "secret").mlsClient(clientId) + } + } + + @Test + fun `getPublicKey should return non empty result`() = runTest { + val (alice) = newClients(aliceId) + assertThat(alice.getPublicKey(defaultCiphersuite).value).isNotEmpty() + } + + @Test + fun `calling generateKeyPackages should return expected number`() = runTest { + val (alice) = newClients(aliceId) + assertThat(alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 10U)).isNotEmpty() + .hasSize(10) + } + + @Test + fun `given new conversation when calling conversationEpoch should return epoch 0`() = runTest { + val (alice) = newClients(aliceId) + alice.createConversation(id, defaultCredentialType) + assertThat(alice.conversationEpoch(id)).isEqualTo(0UL) + } + + @Test + fun `updateKeyingMaterial should process the commit message`() = runTest { + val (alice, bob) = newClients(aliceId, bobId) + + bob.createConversation(id, defaultCredentialType) + + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to aliceKp) + val welcome = bob.addMember(id, aliceMember).welcome!! + bob.commitAccepted(id) + val groupId = alice.processWelcomeMessage(welcome) + + val commit = bob.updateKeyingMaterial(id).commit + + val decrypted = alice.decryptMessage(groupId, commit) + assertThat(decrypted.message).isNull() + assertThat(decrypted.commitDelay).isNull() + assertThat(decrypted.senderClientId).isNull() + assertThat(decrypted.hasEpochChanged).isTrue() + } + + @Test + fun `addMember should allow joining a conversation with a Welcome`() = runTest { + val (alice, bob) = newClients(aliceId, bobId) + + bob.createConversation(id, defaultCredentialType) + + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to aliceKp) + val welcome = bob.addMember(id, aliceMember).welcome!! + val groupId = alice.processWelcomeMessage(welcome) + + assertThat(groupId.value).isEqualTo(id.value) + } + + @Test + fun `joinConversation should generate an Add proposal`() = runTest { + val (alice1, alice2, bob) = newClients(aliceId, aliceId2, bobId) + + bob.createConversation(id, defaultCredentialType) + + val alice1Kp = alice1.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to alice1Kp) + bob.addMember(id, aliceMember) + bob.commitAccepted(id) + + val proposal = alice2.joinConversation(id, 1UL, defaultCiphersuite, defaultCredentialType) + bob.decryptMessage(id, proposal) + val welcome = bob.commitPendingProposals(id)?.welcome!! + bob.commitAccepted(id) + val groupId = alice2.processWelcomeMessage(welcome) + + assertThat(groupId.value).isEqualTo(id.value) + } + + @Test + fun `encryptMessage should encrypt then receiver should decrypt`() = runTest { + val (alice, bob) = newClients(aliceId, bobId) + + bob.createConversation(id, defaultCredentialType) + + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to aliceKp) + val welcome = bob.addMember(id, aliceMember).welcome!! + bob.commitAccepted(id) + val groupId = alice.processWelcomeMessage(welcome) + + val msg = "Hello World !" + val ciphertextMsg = alice.encryptMessage(groupId, msg.toPlaintextMessage()) + assertThat(ciphertextMsg).isNotEqualTo(msg) + + val plaintextMsg = bob.decryptMessage(groupId, ciphertextMsg).message!! + assertThat(String(plaintextMsg)).isNotEmpty().isEqualTo(msg) + } + + @Test + fun `addMember should add members to the MLS group`() = runTest { + val (alice, bob, carol) = newClients(aliceId, bobId, carolId) + + bob.createConversation(id, defaultCredentialType) + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to aliceKp) + val welcome = bob.addMember(id, aliceMember).welcome!! + bob.commitAccepted(id) + + alice.processWelcomeMessage(welcome) + + val carolKp = carol.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val carolMember = mapOf(carolId.toClientId() to carolKp) + val commit = bob.addMember(id, carolMember).commit + + val decrypted = alice.decryptMessage(id, commit) + assertThat(decrypted.message).isNull() + } + + @Test + fun `addMember should return a valid Welcome message`() = runTest { + val (alice, bob) = newClients(aliceId, bobId) + + bob.createConversation(id, defaultCredentialType) + + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to aliceKp) + val welcome = bob.addMember(id, aliceMember).welcome!! + bob.commitAccepted((id)) + + val groupId = alice.processWelcomeMessage(welcome) + assertThat(groupId.value).isEqualTo(id.value) + } + + @Test + fun `removeMember should remove members from the MLS group`() = runTest { + val (alice, bob, carol) = newClients(aliceId, bobId, carolId) + + bob.createConversation(id, defaultCredentialType) + + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val carolKp = carol.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceCarolMember = mapOf(aliceId.toClientId() to aliceKp, carolId.toClientId() to carolKp) + val welcome = bob.addMember(id, aliceCarolMember).welcome!! + bob.commitAccepted(id) + val conversationId = alice.processWelcomeMessage(welcome) + + val carolMember = listOf(carolId.toClientId()) + val commit = bob.removeMember(conversationId, carolMember).commit + + val decrypted = alice.decryptMessage(conversationId, commit) + assertThat(decrypted.message).isNull() + } + + + @Test + fun `sample e2ei enrollment should succeed`() = runTest { + val root = Files.createTempDirectory("mls").toFile() + val keyStore = root.resolve("keystore-$aliceId") + val cc = CoreCryptoCentral(keyStore.absolutePath, "secret") + val enrollment = cc.e2eiNewEnrollment( + clientId = "NjhlMzIxOWFjODRiNDAwYjk0ZGFhZDA2NzExNTEyNTg:6c1866f567616f31@wire.com", + displayName = "Alice Smith", + handle = "alice_wire", + expiryDays = 90u, + ciphersuite = defaultCiphersuite + ) + val directoryResponse = """{ + "newNonce": "https://example.com/acme/new-nonce", + "newAccount": "https://example.com/acme/new-account", + "newOrder": "https://example.com/acme/new-order" + }""".trimIndent().toByteArray() + enrollment.directoryResponse(directoryResponse) + + val previousNonce = "YUVndEZQVTV6ZUNlUkJxRG10c0syQmNWeW1kanlPbjM" + enrollment.newAccountRequest(previousNonce) + + val accountResponse = """{ + "status": "valid", + "orders": "https://example.com/acme/acct/evOfKhNU60wg/orders" + }""".trimIndent().toByteArray() + enrollment.accountResponse(accountResponse) + + enrollment.newOrderRequest(previousNonce) + val orderResponse = """{ + "status": "pending", + "expires": "2037-01-05T14:09:07.99Z", + "notBefore": "2016-01-01T00:00:00Z", + "notAfter": "2037-01-08T00:00:00Z", + "identifiers": [ + { + "type": "wireapp-id", + "value": "{\"name\":\"Alice Smith\",\"domain\":\"wire.com\",\"client-id\":\"im:wireapp=NjhlMzIxOWFjODRiNDAwYjk0ZGFhZDA2NzExNTEyNTg/6c1866f567616f31@wire.com\",\"handle\":\"im:wireapp=alice_wire\"}" + } + ], + "authorizations": [ + "https://example.com/acme/authz/PAniVnsZcis" + ], + "finalize": "https://example.com/acme/order/TOlocE8rfgo/finalize" + }""".trimIndent().toByteArray() + val newOrder = enrollment.newOrderResponse(orderResponse) + + val orderUrl = "https://example.com/acme/wire-acme/order/C7uOXEgg5KPMPtbdE3aVMzv7cJjwUVth" + val authzUrl = newOrder.authorizations[0] + enrollment.newAuthzRequest(authzUrl, previousNonce) + val authzResponse = """{ + "status": "pending", + "expires": "2016-01-02T14:09:30Z", + "identifier": { + "type": "wireapp-id", + "value": "{\"name\":\"Alice Smith\",\"domain\":\"wire.com\",\"client-id\":\"im:wireapp=NjhlMzIxOWFjODRiNDAwYjk0ZGFhZDA2NzExNTEyNTg/6c1866f567616f31@wire.com\",\"handle\":\"im:wireapp=alice_wire\"}" + }, + "challenges": [ + { + "type": "wire-oidc-01", + "url": "https://localhost:55170/acme/acme/challenge/ZelRfonEK02jDGlPCJYHrY8tJKNsH0mw/RNb3z6tvknq7vz2U5DoHsSOGiWQyVtAz", + "status": "pending", + "token": "Gvg5AyOaw0uIQOWKE8lCSIP9nIYwcQiY", + "target": "https://dex/dex" + }, + { + "type": "wire-dpop-01", + "url": "https://localhost:55170/acme/acme/challenge/ZelRfonEK02jDGlPCJYHrY8tJKNsH0mw/0y6hLM0TTOVUkawDhQcw5RB7ONwuhooW", + "status": "pending", + "token": "Gvg5AyOaw0uIQOWKE8lCSIP9nIYwcQiY", + "target": "https://wire.com/clients/6c1866f567616f31/access-token" + } + ] + }""".toByteArray() + enrollment.authzResponse(authzResponse) + + val backendNonce = "U09ZR0tnWE5QS1ozS2d3bkF2eWJyR3ZVUHppSTJsMnU" + enrollment.createDpopToken(backendNonce) + val accessToken = + "eyJhbGciOiJSUzI1NiIsImtpZCI6IjI0NGEzMDE1N2ZhMDMxMmQ2NDU5MWFjODg0NDQ5MDZjZDk4NjZlNTQifQ.eyJpc3MiOiJodHRwOi8vZGV4OjE2MjM4L2RleCIsInN1YiI6IkNsQnBiVHAzYVhKbFlYQndQVTVxYUd4TmVrbDRUMWRHYWs5RVVtbE9SRUYzV1dwck1GcEhSbWhhUkVFeVRucEZlRTVVUlhsT1ZHY3ZObU14T0RZMlpqVTJOell4Tm1Zek1VQjNhWEpsTG1OdmJSSUViR1JoY0EiLCJhdWQiOiJ3aXJlYXBwIiwiZXhwIjoxNjgwNzczMjE4LCJpYXQiOjE2ODA2ODY4MTgsIm5vbmNlIjoiT0t4cVNmel9USm5YbGw1TlpRcUdmdyIsImF0X2hhc2giOiI5VnlmTFdKSm55VEJYVm1LaDRCVV93IiwiY19oYXNoIjoibS1xZXdLN3RQdFNPUzZXN3lXMHpqdyIsIm5hbWUiOiJpbTp3aXJlYXBwPWFsaWNlX3dpcmUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJBbGljZSBTbWl0aCJ9.AemU4vGBsz_7j-_FxCZ1cdMPejwgIgDS7BehajJyeqkAncQVK_FXn5K8ZhFqqpPbaBB7ZVF8mABq8pw_PPnYtM36O8kPfxv5y6lxghlV5vv0aiz49eGl3YCgPvOLKVH7Gop4J4KytyFylsFwzHbDuy0-zzv_Tm9KtHjedrLrf1j9bVTtHosjopzGN3eAnVb3ayXritzJuIoeq3bGkmXrykWcMWJlVNfQl5cwPoGM4OBM_9E8bZ0MTQHi4sG1Dip_zhEfvtRYtM_N0RBRyPyJgWbTb90axl9EKCzcwChUFNdrN_DDMTyyOw8UVRBhupvtS1fzGDMUn4pinJqPlKxIjA" + enrollment.newDpopChallengeRequest(accessToken, previousNonce) + val dpopChallengeResponse = """{ + "type": "wire-dpop-01", + "url": "https://example.com/acme/chall/prV_B7yEyA4", + "status": "valid", + "token": "LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0" + }""".toByteArray() + enrollment.challengeResponse(dpopChallengeResponse) + + enrollment.checkOrderRequest(orderUrl, previousNonce) + val checkOrderResponse = """{ + "status": "ready", + "finalize": "https://localhost:55170/acme/acme/order/FaKNEM5iL79ROLGJdO1DXVzIq5rxPEob/finalize", + "identifiers": [ + { + "type": "wireapp-id", + "value": "{\"name\":\"Alice Smith\",\"domain\":\"wire.com\",\"client-id\":\"im:wireapp=NjhlMzIxOWFjODRiNDAwYjk0ZGFhZDA2NzExNTEyNTg/6c1866f567616f31@wire.com\",\"handle\":\"im:wireapp=alice_wire\"}" + } + ], + "authorizations": [ + "https://localhost:55170/acme/acme/authz/ZelRfonEK02jDGlPCJYHrY8tJKNsH0mw" + ], + "expires": "2032-02-10T14:59:20Z", + "notBefore": "2013-02-09T14:59:20.442908Z", + "notAfter": "2032-02-09T15:59:20.442908Z" + }""".toByteArray() + enrollment.checkOrderResponse(checkOrderResponse) + + enrollment.finalizeRequest(previousNonce) + val finalizeResponse = """{ + "certificate": "https://localhost:55170/acme/acme/certificate/rLhCIYygqzWhUmP1i5tmtZxFUvJPFxSL", + "status": "valid", + "finalize": "https://localhost:55170/acme/acme/order/FaKNEM5iL79ROLGJdO1DXVzIq5rxPEob/finalize", + "identifiers": [ + { + "type": "wireapp-id", + "value": "{\"name\":\"Alice Smith\",\"domain\":\"wire.com\",\"client-id\":\"im:wireapp=NjhlMzIxOWFjODRiNDAwYjk0ZGFhZDA2NzExNTEyNTg/6c1866f567616f31@wire.com\",\"handle\":\"im:wireapp=alice_wire\"}" + } + ], + "authorizations": [ + "https://localhost:55170/acme/acme/authz/ZelRfonEK02jDGlPCJYHrY8tJKNsH0mw" + ], + "expires": "2032-02-10T14:59:20Z", + "notBefore": "2013-02-09T14:59:20.442908Z", + "notAfter": "2032-02-09T15:59:20.442908Z" + }""".toByteArray() + enrollment.finalizeResponse(finalizeResponse) + + enrollment.certificateRequest(previousNonce) + } + + @Test + fun `conversation should be degraded when at least 1 of the members uses a Basic credential`() = runTest { + val (alice, bob) = newClients(aliceId, bobId) + + bob.createConversation(id, defaultCredentialType) + + val aliceKp = alice.generateKeyPackages(defaultCiphersuite, defaultCredentialType, 1U).first() + val aliceMember = mapOf(aliceId.toClientId() to aliceKp) + val welcome = bob.addMember(id, aliceMember).welcome!! + bob.commitAccepted(id) + val groupId = alice.processWelcomeMessage(welcome) + + assertThat(alice.e2eiConversationState(groupId)).isEqualTo(E2eiConversationState.NOT_ENABLED) + assertThat(bob.e2eiConversationState(groupId)).isEqualTo(E2eiConversationState.NOT_ENABLED) + } +} diff --git a/crypto-ffi/bindings/android/src/test/kotlin/com/wire/crypto/client/ProteusClientTest.kt b/crypto-ffi/bindings/android/src/test/kotlin/com/wire/crypto/client/ProteusClientTest.kt new file mode 100644 index 0000000000..48ad90e8c2 --- /dev/null +++ b/crypto-ffi/bindings/android/src/test/kotlin/com/wire/crypto/client/ProteusClientTest.kt @@ -0,0 +1,124 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +import com.wire.crypto.client.* +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import java.nio.file.Files +import kotlin.test.* + +@OptIn(ExperimentalCoroutinesApi::class) +internal class ProteusClientTest { + + companion object { + private val alice = "alice1".toClientId() + private val bob = "bob1".toClientId() + private const val aliceSessionId = "alice1_session1" + private const val bobSessionId = "bob1_session1" + } + + private suspend fun newProteusClient(clientId: ClientId): ProteusClient = runBlocking { + val root = Files.createTempDirectory("mls").toFile() + val keyStore = root.resolve("keystore-$clientId") + CoreCryptoCentral(keyStore.absolutePath, "secret").proteusClient() + } + + @Test + fun givenProteusClient_whenCallingNewLastKey_thenItReturnsALastPreKey() = runTest { + val aliceClient = newProteusClient(alice) + val lastPreKey = aliceClient.newLastPreKey() + assertEquals(65535u, lastPreKey.id) + } + + @Test + fun givenProteusClient_whenCallingNewPreKeys_thenItReturnsAListOfPreKeys() = runTest { + val aliceClient = newProteusClient(alice) + val preKeyList = aliceClient.newPreKeys(0, 10) + assertEquals(preKeyList.size, 10) + } + + @Test + fun givenIncomingPreKeyMessage_whenCallingDecrypt_thenMessageIsDecrypted() = runTest { + val aliceClient = newProteusClient(alice) + val bobClient = newProteusClient(bob) + + val message = "Hi Alice!" + val aliceKey = aliceClient.newPreKeys(0, 10).first() + val encryptedMessage = bobClient.encryptWithPreKey(message.encodeToByteArray(), aliceKey, aliceSessionId) + val decryptedMessage = aliceClient.decrypt(encryptedMessage, bobSessionId) + assertEquals(message, decryptedMessage.decodeToString()) + } + + @Test + fun givenSessionAlreadyExists_whenCallingDecrypt_thenMessageIsDecrypted() = runTest { + val aliceClient = newProteusClient(alice) + val bobClient = newProteusClient(bob) + val aliceKey = aliceClient.newPreKeys(0, 10).first() + val message1 = "Hi Alice!" + val encryptedMessage1 = bobClient.encryptWithPreKey(message1.encodeToByteArray(), aliceKey, aliceSessionId) + aliceClient.decrypt(encryptedMessage1, bobSessionId) + + val message2 = "Hi again Alice!" + val encryptedMessage2 = bobClient.encrypt(message2.encodeToByteArray(), aliceSessionId) + val decryptedMessage2 = aliceClient.decrypt(encryptedMessage2, bobSessionId) + + assertEquals(message2, decryptedMessage2.decodeToString()) + } + + @Test + fun givenReceivingSameMessageTwice_whenCallingDecrypt_thenDuplicateMessageError() = runTest { + val aliceClient = newProteusClient(alice) + val bobClient = newProteusClient(bob) + val aliceKey = aliceClient.newPreKeys(0, 10).first() + val message1 = "Hi Alice!" + val encryptedMessage1 = bobClient.encryptWithPreKey(message1.encodeToByteArray(), aliceKey, aliceSessionId) + aliceClient.decrypt(encryptedMessage1, bobSessionId) + + val exception: ProteusException = assertFailsWith { + aliceClient.decrypt(encryptedMessage1, bobSessionId) + } + assertEquals(ProteusException.Code.DUPLICATE_MESSAGE, exception.code) + } + + @Test + fun givenMissingSession_whenCallingEncryptBatched_thenMissingSessionAreIgnored() = runTest { + val aliceClient = newProteusClient(alice) + val bobClient = newProteusClient(bob) + val aliceKey = aliceClient.newPreKeys(0, 10).first() + val message1 = "Hi Alice!" + bobClient.createSession(aliceKey, aliceSessionId) + + val missingAliceSessionId = "missing_session" + val encryptedMessages = + bobClient.encryptBatched(message1.encodeToByteArray(), listOf(aliceSessionId, missingAliceSessionId)) + + assertEquals(1, encryptedMessages.size) + assertTrue(encryptedMessages.containsKey(aliceSessionId)) + } + + @Test + fun givenNoSessionExists_whenCallingCreateSession_thenSessionIsCreated() = runTest { + val aliceClient = newProteusClient(alice) + val bobClient = newProteusClient(bob) + + val aliceKey = aliceClient.newPreKeys(0, 10).first() + bobClient.createSession(aliceKey, aliceSessionId) + assertNotNull(bobClient.encrypt("Hello World".encodeToByteArray(), aliceSessionId)) + } +} diff --git a/crypto-ffi/bindings/js/CoreCrypto.ts b/crypto-ffi/bindings/js/CoreCrypto.ts index 0929a73bc1..190ec37b23 100644 --- a/crypto-ffi/bindings/js/CoreCrypto.ts +++ b/crypto-ffi/bindings/js/CoreCrypto.ts @@ -919,7 +919,12 @@ export class CoreCrypto { } /** - * Decrypts a message for a given conversation + * Decrypts a message for a given conversation. + * + * Note: you should catch & ignore the following error reasons: + * * "We already decrypted this message once" + * * "You tried to join with an external commit but did not merge it yet. We will reapply this message for you when you merge your external commit" + * * "Incoming message is for a future epoch. We will buffer it until the commit for that epoch arrives" * * @param conversationId - The ID of the conversation * @param payload - The encrypted message buffer @@ -1337,6 +1342,7 @@ export class CoreCrypto { * and deletes the temporary one. This step makes the group operational and ready to encrypt/decrypt message * * @param conversationId - The ID of the conversation + * @returns the messages from current epoch which had been buffered, if any */ async mergePendingGroupFromExternalCommit(conversationId: ConversationId): Promise { return await CoreCryptoError.asyncMapErr(this.#cc.merge_pending_group_from_external_commit(conversationId)); @@ -1358,8 +1364,9 @@ export class CoreCrypto { * into the local group state * * @param conversationId - The group's ID + * @returns the messages from current epoch which had been buffered, if any */ - async commitAccepted(conversationId: ConversationId): Promise { + async commitAccepted(conversationId: ConversationId): Promise { return await CoreCryptoError.asyncMapErr(this.#cc.commit_accepted(conversationId)); } diff --git a/crypto-ffi/bindings/kt/main/com/wire/crypto/client/MLSClient.kt b/crypto-ffi/bindings/kt/main/com/wire/crypto/client/MLSClient.kt index 670ddddcf5..7c256a0b60 100644 --- a/crypto-ffi/bindings/kt/main/com/wire/crypto/client/MLSClient.kt +++ b/crypto-ffi/bindings/kt/main/com/wire/crypto/client/MLSClient.kt @@ -105,7 +105,7 @@ interface MLSClient { addTrustAnchors: List, ): CommitBundle? - suspend fun commitAccepted(groupId: MLSGroupId) + suspend fun commitAccepted(groupId: MLSGroupId): List? suspend fun commitPendingProposals(groupId: MLSGroupId): CommitBundle? @@ -234,7 +234,7 @@ class MLSClientImpl( return cc.decryptMessage(groupId.toUByteList(), message.toUByteList()).toDecryptedMessageBundle() } - override suspend fun commitAccepted(groupId: MLSGroupId) { + override suspend fun commitAccepted(groupId: MLSGroupId): List? { return cc.commitAccepted(groupId.toUByteList()) } diff --git a/crypto-ffi/bindings/swift/Sources/CoreCrypto/CoreCrypto.swift b/crypto-ffi/bindings/swift/Sources/CoreCrypto/CoreCrypto.swift index 497b5a4b4d..42c8a95c61 100644 --- a/crypto-ffi/bindings/swift/Sources/CoreCrypto/CoreCrypto.swift +++ b/crypto-ffi/bindings/swift/Sources/CoreCrypto/CoreCrypto.swift @@ -723,6 +723,10 @@ public class CoreCryptoWrapper { } /// Deserializes a TLS-serialized message, then deciphers it + /// Note: you should catch & ignore the following error: + /// - `DuplicateMessage` + /// - `UnmergedPendingGroup` + /// - `BufferedFutureMessage` /// /// - parameter conversationId: conversation identifier /// - parameter payload: the encrypted message as a byte array diff --git a/crypto-ffi/src/CoreCrypto.udl b/crypto-ffi/src/CoreCrypto.udl index 73b5c1f63c..4c6e26acbe 100644 --- a/crypto-ffi/src/CoreCrypto.udl +++ b/crypto-ffi/src/CoreCrypto.udl @@ -164,6 +164,7 @@ enum CryptoError { "InvalidHashReference", "DuplicateMessage", "WrongEpoch", + "BufferedFutureMessage", "DecryptionError", "HexDecodeError", "ProteusError", diff --git a/crypto-ffi/src/generic.rs b/crypto-ffi/src/generic.rs index 0345a0c650..0ca52f9a5d 100644 --- a/crypto-ffi/src/generic.rs +++ b/crypto-ffi/src/generic.rs @@ -863,8 +863,17 @@ impl CoreCrypto { } /// See [core_crypto::mls::MlsCentral::commit_accepted] - pub async fn commit_accepted(&self, conversation_id: Vec) -> CryptoResult<()> { - self.central.lock().await.commit_accepted(&conversation_id).await + pub async fn commit_accepted(&self, conversation_id: Vec) -> CryptoResult>> { + if let Some(decrypted_messages) = self.central.lock().await.commit_accepted(&conversation_id).await? { + return Ok(Some( + decrypted_messages + .into_iter() + .map(DecryptedMessage::try_from) + .collect::>>()?, + )); + } + + Ok(None) } /// See [core_crypto::mls::MlsCentral::clear_pending_proposal] diff --git a/crypto-ffi/src/wasm.rs b/crypto-ffi/src/wasm.rs index 6bc6127036..913a90c5ea 100644 --- a/crypto-ffi/src/wasm.rs +++ b/crypto-ffi/src/wasm.rs @@ -1353,7 +1353,7 @@ impl CoreCrypto { /// see [core_crypto::mls::MlsCentral::new_conversation] pub fn create_conversation( &self, - conversation_id: Box<[u8]>, + conversation_id: ConversationId, creator_credential_type: CredentialType, config: ConversationConfiguration, ) -> Promise { @@ -1378,14 +1378,14 @@ impl CoreCrypto { /// Returns [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::conversation_epoch] - pub fn conversation_epoch(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn conversation_epoch(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { WasmCryptoResult::Ok( this.write() .await - .conversation_epoch(&conversation_id.into()) + .conversation_epoch(&conversation_id) .await .map_err(CoreCryptoError::from)? .into(), @@ -1398,17 +1398,15 @@ impl CoreCrypto { /// Returns: [`bool`] /// /// see [core_crypto::mls::MlsCentral::conversation_exists] - pub fn conversation_exists(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn conversation_exists(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { - WasmCryptoResult::Ok( - if this.write().await.conversation_exists(&conversation_id.into()).await { - JsValue::TRUE - } else { - JsValue::FALSE - }, - ) + WasmCryptoResult::Ok(if this.write().await.conversation_exists(&conversation_id).await { + JsValue::TRUE + } else { + JsValue::FALSE + }) } .err_into(), ) @@ -1440,7 +1438,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult>`] /// /// see [core_crypto::mls::MlsCentral::add_members_to_conversation] - pub fn add_clients_to_conversation(&self, conversation_id: Box<[u8]>, clients: Box<[JsValue]>) -> Promise { + pub fn add_clients_to_conversation(&self, conversation_id: ConversationId, clients: Box<[JsValue]>) -> Promise { let this = self.inner.clone(); future_to_promise( @@ -1454,7 +1452,6 @@ impl CoreCrypto { let mut central = this.write().await; let backend = central.provider(); let mut members = Invitee::group_to_conversation_member(invitees, backend)?; - let conversation_id = conversation_id.into(); let commit = central .add_members_to_conversation(&conversation_id, &mut members) .await?; @@ -1468,7 +1465,11 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult>`] /// /// see [core_crypto::mls::MlsCentral::remove_members_from_conversation] - pub fn remove_clients_from_conversation(&self, conversation_id: Box<[u8]>, clients: Box<[Uint8Array]>) -> Promise { + pub fn remove_clients_from_conversation( + &self, + conversation_id: ConversationId, + clients: Box<[Uint8Array]>, + ) -> Promise { let this = self.inner.clone(); future_to_promise( @@ -1479,7 +1480,6 @@ impl CoreCrypto { .map(|c| c.to_vec().into()) .collect::>(); - let conversation_id = conversation_id.into(); let mut central = this.write().await; let commit = central .remove_members_from_conversation(&conversation_id, &clients) @@ -1517,13 +1517,12 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::update_keying_material] - pub fn update_keying_material(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn update_keying_material(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { let mut central = this.write().await; - let conversation_id = conversation_id.into(); let commit = central .update_keying_material(&conversation_id) .await @@ -1538,13 +1537,12 @@ impl CoreCrypto { } /// see [core_crypto::mls::MlsCentral::commit_pending_proposals] - pub fn commit_pending_proposals(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn commit_pending_proposals(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { let mut central = this.write().await; - let conversation_id = conversation_id.into(); let commit: Option = central .commit_pending_proposals(&conversation_id) .await? @@ -1560,11 +1558,10 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult<()>`] /// /// see [core_crypto::mls::MlsCentral::wipe_conversation] - pub fn wipe_conversation(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn wipe_conversation(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { - let conversation_id = conversation_id.into(); let mut central = this.write().await; central .wipe_conversation(&conversation_id) @@ -1579,7 +1576,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::decrypt_message] - pub fn decrypt_message(&self, conversation_id: Box<[u8]>, payload: Box<[u8]>) -> Promise { + pub fn decrypt_message(&self, conversation_id: ConversationId, payload: Box<[u8]>) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -1601,7 +1598,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::encrypt_message] - pub fn encrypt_message(&self, conversation_id: Box<[u8]>, message: Box<[u8]>) -> Promise { + pub fn encrypt_message(&self, conversation_id: ConversationId, message: Box<[u8]>) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -1624,7 +1621,7 @@ impl CoreCrypto { /// see [core_crypto::mls::MlsCentral::update_trust_anchors_from_conversation] pub fn update_trust_anchors_from_conversation( &self, - conversation_id: Box<[u8]>, + conversation_id: ConversationId, remove_domain_names: Box<[js_sys::JsString]>, add_trust_anchors: js_sys::Array, ) -> Promise { @@ -1663,7 +1660,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::new_add_proposal] - pub fn new_add_proposal(&self, conversation_id: Box<[u8]>, keypackage: Box<[u8]>) -> Promise { + pub fn new_add_proposal(&self, conversation_id: ConversationId, keypackage: Box<[u8]>) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -1689,7 +1686,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::new_update_proposal] - pub fn new_update_proposal(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn new_update_proposal(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -1709,7 +1706,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::new_remove_proposal] - pub fn new_remove_proposal(&self, conversation_id: Box<[u8]>, client_id: FfiClientId) -> Promise { + pub fn new_remove_proposal(&self, conversation_id: ConversationId, client_id: FfiClientId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -1732,7 +1729,7 @@ impl CoreCrypto { /// see [core_crypto::mls::MlsCentral::new_external_add_proposal] pub fn new_external_add_proposal( &self, - conversation_id: Box<[u8]>, + conversation_id: ConversationId, epoch: u32, ciphersuite: Ciphersuite, credential_type: CredentialType, @@ -1843,15 +1840,24 @@ impl CoreCrypto { } /// see [core_crypto::mls::MlsCentral::commit_accepted] - pub fn commit_accepted(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn commit_accepted(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { - this.write() + if let Some(decrypted_messages) = this + .write() .await - .commit_accepted(&conversation_id.to_vec()) + .commit_accepted(&conversation_id) .await - .map_err(CoreCryptoError::from)?; + .map_err(CoreCryptoError::from)? + { + let messages = decrypted_messages + .into_iter() + .map(DecryptedMessage::try_from) + .collect::>>()?; + + return WasmCryptoResult::Ok(serde_wasm_bindgen::to_value(&messages)?); + } WasmCryptoResult::Ok(JsValue::UNDEFINED) } @@ -1860,7 +1866,7 @@ impl CoreCrypto { } /// see [core_crypto::mls::MlsCentral::clear_pending_proposal] - pub fn clear_pending_proposal(&self, conversation_id: Box<[u8]>, proposal_ref: Box<[u8]>) -> Promise { + pub fn clear_pending_proposal(&self, conversation_id: ConversationId, proposal_ref: Box<[u8]>) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -1877,7 +1883,7 @@ impl CoreCrypto { } /// see [core_crypto::mls::MlsCentral::clear_pending_commit] - pub fn clear_pending_commit(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn clear_pending_commit(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -2256,7 +2262,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult>`] /// /// see [core_crypto::mls::MlsCentral::export_secret_key] - pub fn export_secret_key(&self, conversation_id: Box<[u8]>, key_length: usize) -> Promise { + pub fn export_secret_key(&self, conversation_id: ConversationId, key_length: usize) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -2275,7 +2281,7 @@ impl CoreCrypto { /// Returns: [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::get_client_ids] - pub fn get_client_ids(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn get_client_ids(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { @@ -2472,14 +2478,14 @@ impl CoreCrypto { /// Returns [`WasmCryptoResult`] /// /// see [core_crypto::mls::MlsCentral::e2ei_conversation_state] - pub fn e2ei_conversation_state(&self, conversation_id: Box<[u8]>) -> Promise { + pub fn e2ei_conversation_state(&self, conversation_id: ConversationId) -> Promise { let this = self.inner.clone(); future_to_promise( async move { let state: E2eiConversationState = this .write() .await - .e2ei_conversation_state(&conversation_id.into()) + .e2ei_conversation_state(&conversation_id) .await .map_err(CoreCryptoError::from)? .into(); diff --git a/crypto/src/error.rs b/crypto/src/error.rs index 15e7bc3347..3165904477 100644 --- a/crypto/src/error.rs +++ b/crypto/src/error.rs @@ -122,6 +122,9 @@ pub enum CryptoError { /// Incoming message is for the wrong epoch #[error("Incoming message is for the wrong epoch")] WrongEpoch, + /// Incoming message is for a future epoch. We will buffer it until the commit for that epoch arrives + #[error("Incoming message is for a future epoch. We will buffer it until the commit for that epoch arrives")] + BufferedFutureMessage, /// Proteus Error Wrapper #[error(transparent)] ProteusError(#[from] ProteusError), diff --git a/crypto/src/mls/buffer_external_commit.rs b/crypto/src/mls/buffer_external_commit.rs index 54c11dfa47..6941d58e43 100644 --- a/crypto/src/mls/buffer_external_commit.rs +++ b/crypto/src/mls/buffer_external_commit.rs @@ -5,13 +5,8 @@ //! //! Feel free to delete all of this when the issue is fixed on the DS side ! -use crate::prelude::{ - ConversationId, CryptoError, CryptoResult, MlsCentral, MlsConversation, MlsConversationDecryptMessage, -}; -use crate::MlsError; -use core_crypto_keystore::entities::{EntityFindParams, MlsPendingMessage, PersistedMlsPendingGroup}; -use openmls::prelude::{MlsMessageIn, MlsMessageInBody}; -use tls_codec::Deserialize; +use crate::prelude::{ConversationId, CryptoError, CryptoResult, MlsCentral, MlsConversationDecryptMessage}; +use core_crypto_keystore::entities::{MlsPendingMessage, PersistedMlsPendingGroup}; impl MlsCentral { pub(crate) async fn handle_when_group_is_pending( @@ -31,55 +26,6 @@ impl MlsCentral { keystore.save::(pending_msg).await?; Err(CryptoError::UnmergedPendingGroup) } - - pub(crate) async fn restore_pending_messages( - &mut self, - conversation: &mut MlsConversation, - ) -> CryptoResult>> { - let keystore = self.mls_backend.borrow_keystore(); - - let mut pending_messages = keystore - .find_all::(EntityFindParams::default()) - .await? - .into_iter() - .filter(|pm| pm.id == conversation.id.as_slice()) - .try_fold(vec![], |mut acc, m| { - let msg = MlsMessageIn::tls_deserialize_bytes(m.message.as_slice()).map_err(MlsError::from)?; - let ct = match msg.body_as_ref() { - MlsMessageInBody::PublicMessage(m) => Ok(m.content_type()), - MlsMessageInBody::PrivateMessage(m) => Ok(m.content_type()), - _ => Err(CryptoError::ImplementationError), - }?; - acc.push((ct as u8, msg)); - CryptoResult::Ok(acc) - })?; - - // We want to restore application messages first, then Proposals & finally Commits - // luckily for us that's the exact same order as the [ContentType] enum - pending_messages.sort_by(|(a, _), (b, _)| a.cmp(b)); - - let mut decrypted_messages = vec![]; - for (_, m) in pending_messages { - let parent_conversation = if let Some(parent_id) = &conversation.parent_id { - Some( - self.get_conversation(parent_id) - .await - .map_err(|_| CryptoError::ParentGroupNotFound)?, - ) - } else { - None - }; - let callbacks = self.callbacks.as_ref().map(|boxed| boxed.as_ref()); - let decrypted = conversation - .decrypt_message(m, parent_conversation, self.mls_client()?, &self.mls_backend, callbacks) - .await?; - decrypted_messages.push(decrypted); - } - - let decrypted_messages = (!decrypted_messages.is_empty()).then_some(decrypted_messages); - - Ok(decrypted_messages) - } } #[cfg(test)] diff --git a/crypto/src/mls/conversation/buffer_messages.rs b/crypto/src/mls/conversation/buffer_messages.rs new file mode 100644 index 0000000000..6437a864f4 --- /dev/null +++ b/crypto/src/mls/conversation/buffer_messages.rs @@ -0,0 +1,197 @@ +//! This file is intended to fix some issues we have with the Delivery Service. Sometimes, clients +//! receive for the next epoch before receiving the commit for this epoch. +//! +//! Feel free to delete all of this when the issue is fixed on the DS side ! + +use crate::prelude::{ + ConversationId, CryptoError, CryptoResult, MlsCentral, MlsConversation, MlsConversationDecryptMessage, +}; +use crate::MlsError; +use core_crypto_keystore::entities::{EntityFindParams, MlsPendingMessage}; +use openmls::prelude::{MlsMessageIn, MlsMessageInBody}; +use tls_codec::Deserialize; + +impl MlsCentral { + pub(crate) async fn handle_future_message( + &mut self, + id: &ConversationId, + message: impl AsRef<[u8]>, + ) -> CryptoResult { + let keystore = self.mls_backend.borrow_keystore(); + + let pending_msg = MlsPendingMessage { + id: id.clone(), + message: message.as_ref().to_vec(), + }; + keystore.save::(pending_msg).await?; + Err(CryptoError::BufferedFutureMessage) + } + + pub(crate) async fn restore_pending_messages( + &mut self, + conversation: &mut MlsConversation, + ) -> CryptoResult>> { + let keystore = self.mls_backend.borrow_keystore(); + + let mut pending_messages = keystore + .find_all::(EntityFindParams::default()) + .await? + .into_iter() + .filter(|pm| pm.id == conversation.id.as_slice()) + .try_fold(vec![], |mut acc, m| { + let msg = MlsMessageIn::tls_deserialize_bytes(m.message.as_slice()).map_err(MlsError::from)?; + let ct = match msg.body_as_ref() { + MlsMessageInBody::PublicMessage(m) => Ok(m.content_type()), + MlsMessageInBody::PrivateMessage(m) => Ok(m.content_type()), + _ => Err(CryptoError::ImplementationError), + }?; + acc.push((ct as u8, msg)); + CryptoResult::Ok(acc) + })?; + + // We want to restore application messages first, then Proposals & finally Commits + // luckily for us that's the exact same order as the [ContentType] enum + pending_messages.sort_by(|(a, _), (b, _)| a.cmp(b)); + + let mut decrypted_messages = vec![]; + for (_, m) in pending_messages { + let parent_conversation = if let Some(parent_id) = &conversation.parent_id { + Some( + self.get_conversation(parent_id) + .await + .map_err(|_| CryptoError::ParentGroupNotFound)?, + ) + } else { + None + }; + let callbacks = self.callbacks.as_ref().map(|boxed| boxed.as_ref()); + let decrypted = conversation + .decrypt_message(m, parent_conversation, self.mls_client()?, &self.mls_backend, callbacks) + .await?; + decrypted_messages.push(decrypted); + } + + let decrypted_messages = (!decrypted_messages.is_empty()).then_some(decrypted_messages); + + Ok(decrypted_messages) + } +} + +#[cfg(test)] +pub mod tests { + use crate::{test_utils::*, CryptoError}; + use core_crypto_keystore::entities::MlsPendingMessage; + use openmls_traits::OpenMlsCryptoProvider; + use wasm_bindgen_test::*; + + wasm_bindgen_test_configure!(run_in_browser); + + #[apply(all_cred_cipher)] + #[wasm_bindgen_test] + pub async fn should_buffer_and_reapply_messages_after_commit_merged(case: TestCase) { + run_test_with_client_ids( + case.clone(), + ["alice", "bob", "charlie", "debbie"], + move |[mut alice_central, mut bob_central, mut charlie_central, mut debbie_central]| { + Box::pin(async move { + let id = conversation_id(); + alice_central + .new_conversation(id.clone(), case.credential_type, case.cfg.clone()) + .await + .unwrap(); + alice_central.invite_all(&case, &id, [&mut bob_central]).await.unwrap(); + + // Bob creates a commit but won't merge it immediately + let unmerged_commit = bob_central.update_keying_material(&id).await.unwrap(); + + // Alice decrypts the commit... + alice_central + .decrypt_message(&id, unmerged_commit.commit.to_bytes().unwrap()) + .await + .unwrap(); + + // Meanwhile Debbie joins the party by creating an external proposal + let epoch = alice_central.conversation_epoch(&id).await.unwrap(); + let external_proposal = debbie_central + .new_external_add_proposal(id.clone(), epoch.into(), case.ciphersuite(), case.credential_type) + .await + .unwrap(); + + // ...then Alice generates new messages for this epoch + let app_msg = alice_central.encrypt_message(&id, b"Hello Bob !").await.unwrap(); + let proposal = alice_central.new_update_proposal(&id).await.unwrap().proposal; + alice_central + .decrypt_message(&id, external_proposal.to_bytes().unwrap()) + .await + .unwrap(); + let charlie = charlie_central.rand_member(&case).await; + let commit = alice_central + .add_members_to_conversation(&id, &mut [charlie]) + .await + .unwrap(); + alice_central.commit_accepted(&id).await.unwrap(); + charlie_central + .process_welcome_message(commit.welcome.clone().into(), case.custom_cfg()) + .await + .unwrap(); + debbie_central + .process_welcome_message(commit.welcome.clone().into(), case.custom_cfg()) + .await + .unwrap(); + + // And now Bob will have to decrypt those messages while he hasn't yet merged its commit + // To add more fun, he will buffer the messages in exactly the wrong order (to make + // sure he reapplies them in the right order afterwards) + let messages = [commit.commit, external_proposal, proposal].map(|m| m.to_bytes().unwrap()); + for m in messages { + let decrypt = bob_central.decrypt_message(&id, m).await; + assert!(matches!(decrypt.unwrap_err(), CryptoError::BufferedFutureMessage)); + } + let decrypt = bob_central.decrypt_message(&id, app_msg).await; + assert!(matches!(decrypt.unwrap_err(), CryptoError::BufferedFutureMessage)); + + // Finally, Bob receives the green light from the DS and he can merge the external commit + let Some(restored_messages) = bob_central.commit_accepted(&id).await.unwrap() else { + panic!("Alice's messages should have been restored at this point"); + }; + for (i, m) in restored_messages.into_iter().enumerate() { + match i { + 0 => { + // this is the application message + assert_eq!(&m.app_msg.unwrap(), b"Hello Bob !"); + assert!(!m.has_epoch_changed); + } + 1 | 2 => { + // this is either the member or the external proposal + assert!(m.app_msg.is_none()); + assert!(!m.has_epoch_changed); + } + 3 => { + // this is the commit + assert!(m.app_msg.is_none()); + assert!(m.has_epoch_changed); + } + _ => unreachable!(), + } + } + // because external commit got merged + assert!(bob_central.try_talk_to(&id, &mut alice_central).await.is_ok()); + // because Alice's commit got merged + assert!(bob_central.try_talk_to(&id, &mut charlie_central).await.is_ok()); + // because Debbie's external proposal got merged through the commit + assert!(bob_central.try_talk_to(&id, &mut debbie_central).await.is_ok()); + + // After merging we should erase all those pending messages + let count_pending_messages = bob_central + .mls_backend + .key_store() + .count::() + .await + .unwrap(); + assert_eq!(count_pending_messages, 0); + }) + }, + ) + .await + } +} diff --git a/crypto/src/mls/conversation/decrypt.rs b/crypto/src/mls/conversation/decrypt.rs index 2762294756..5a23a73d94 100644 --- a/crypto/src/mls/conversation/decrypt.rs +++ b/crypto/src/mls/conversation/decrypt.rs @@ -181,6 +181,7 @@ impl MlsConversation { )) } }; + let msg_epoch = protocol_message.epoch().as_u64(); let processed_msg = self .group .process_message(backend, protocol_message) @@ -192,6 +193,10 @@ impl MlsConversation { ProcessMessageError::ValidationError(ValidationError::WrongEpoch) => { if is_duplicate { CryptoError::DuplicateMessage + } else if msg_epoch == self.group.epoch().as_u64() + 1 { + // limit to next epoch otherwise if we were buffering a commit for epoch + 2 + // we would fail when trying to decrypt it in [MlsCentral::commit_accepted] + CryptoError::BufferedFutureMessage } else { CryptoError::WrongEpoch } @@ -236,7 +241,6 @@ impl MlsCentral { let Ok(conversation) = self.get_conversation(id).await else { return self.handle_when_group_is_pending(id, message).await; }; - // let conversation = self.get_conversation(id).await?; let parent_conversation = self.get_parent_conversation(&conversation).await?; let decrypt_message = conversation .write() @@ -248,7 +252,12 @@ impl MlsCentral { &self.mls_backend, self.callbacks.as_ref().map(|boxed| boxed.as_ref()), ) - .await?; + .await; + + let decrypt_message = match decrypt_message { + Err(CryptoError::BufferedFutureMessage) => self.handle_future_message(id, message).await?, + _ => decrypt_message?, + }; if !decrypt_message.is_active { self.wipe_conversation(id).await?; @@ -1050,7 +1059,7 @@ pub mod tests { // which Bob cannot decrypt because of Post CompromiseSecurity let decrypt = bob_central.decrypt_message(&id, &encrypted).await; - assert!(matches!(decrypt.unwrap_err(), CryptoError::WrongEpoch)); + assert!(matches!(decrypt.unwrap_err(), CryptoError::BufferedFutureMessage)); bob_central .decrypt_message(&id, commit.to_bytes().unwrap()) diff --git a/crypto/src/mls/conversation/handshake.rs b/crypto/src/mls/conversation/handshake.rs index be3a547f36..0eea64b259 100644 --- a/crypto/src/mls/conversation/handshake.rs +++ b/crypto/src/mls/conversation/handshake.rs @@ -1368,7 +1368,7 @@ pub mod tests { // fails when a commit is skipped let out_of_order = bob_central.decrypt_message(&id, &commit2).await; - assert!(matches!(out_of_order.unwrap_err(), CryptoError::WrongEpoch)); + assert!(matches!(out_of_order.unwrap_err(), CryptoError::BufferedFutureMessage)); // works in the right order though assert!(bob_central.decrypt_message(&id, &commit1).await.is_ok()); assert!(bob_central.decrypt_message(&id, &commit2).await.is_ok()); diff --git a/crypto/src/mls/conversation/merge.rs b/crypto/src/mls/conversation/merge.rs index ef6c5fb69e..62b7ec7f38 100644 --- a/crypto/src/mls/conversation/merge.rs +++ b/crypto/src/mls/conversation/merge.rs @@ -11,13 +11,13 @@ //! | 1+ pend. Proposal | ❌ | ✅ | //! -use core_crypto_keystore::entities::MlsEncryptionKeyPair; +use core_crypto_keystore::entities::{MlsEncryptionKeyPair, MlsPendingMessage}; use openmls::prelude::MlsGroupStateError; use openmls_traits::OpenMlsCryptoProvider; use mls_crypto_provider::MlsCryptoProvider; -use crate::prelude::MlsProposalRef; +use crate::prelude::{MlsConversationDecryptMessage, MlsProposalRef}; use crate::{ mls::{ConversationId, MlsCentral, MlsConversation}, CryptoError, CryptoResult, MlsError, @@ -91,13 +91,19 @@ impl MlsCentral { /// to be used for the new epoch. /// We can now safely "merge" it (effectively apply the commit to the group) and update it /// in the keystore. The previous can be discarded to respect Forward Secrecy. - pub async fn commit_accepted(&mut self, conversation_id: &ConversationId) -> CryptoResult<()> { - self.get_conversation(conversation_id) - .await? - .write() - .await - .commit_accepted(&self.mls_backend) - .await + pub async fn commit_accepted( + &mut self, + id: &ConversationId, + ) -> CryptoResult>> { + let conv = self.get_conversation(id).await?; + let mut conv = conv.write().await; + conv.commit_accepted(&self.mls_backend).await?; + + let pending_messages = self.restore_pending_messages(&mut conv).await?; + if pending_messages.is_some() { + self.mls_backend.key_store().remove::(id).await?; + } + Ok(pending_messages) } /// Allows to remove a pending (uncommitted) proposal. Use this when backend rejects the proposal diff --git a/crypto/src/mls/conversation/mod.rs b/crypto/src/mls/conversation/mod.rs index 335af407e3..cdd9cd5f9d 100644 --- a/crypto/src/mls/conversation/mod.rs +++ b/crypto/src/mls/conversation/mod.rs @@ -43,6 +43,7 @@ use crate::{ prelude::{CryptoError, CryptoResult, MlsCiphersuite, MlsCredentialType, MlsError}, }; +mod buffer_messages; mod commit_delay; pub mod config; #[cfg(test)]