diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
index 45879a3c9c..207937d393 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt
@@ -37,7 +37,6 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic
 import org.matrix.android.sdk.api.session.events.model.Content
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-import org.matrix.android.sdk.internal.crypto.NewSessionListener
 
 interface CryptoService {
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt
index 73cbf5fb78..8fe2d160f9 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/NewSessionListener.kt
@@ -23,8 +23,7 @@ interface NewSessionListener {
 
     /**
      * @param roomId the room id where the new Megolm session has been created for, may be null when importing from external sessions
-     * @param senderKey the sender key of the device which the Megolm session is shared with
      * @param sessionId the session id of the Megolm session
      */
-    fun onNewSession(roomId: String?, senderKey: String, sessionId: String)
+    fun onNewSession(roomId: String?, sessionId: String)
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt
index 5e58893def..006d6da310 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/crosssigning/CrossSigningService.kt
@@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.crypto.crosssigning
 
 import kotlinx.coroutines.flow.Flow
 import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
-import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
+import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
 import org.matrix.android.sdk.api.util.Optional
 
 interface CrossSigningService {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt
index dc5567e908..02f05e6b01 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXUsersDevicesMap.kt
@@ -104,6 +104,11 @@ class MXUsersDevicesMap<E> {
         map.clear()
     }
 
+    fun join(other: Map<out String, HashMap<String, E>>) {
+        map.putAll(other)
+    }
+
+
     /**
      * Add entries from another MXUsersDevicesMap
      *
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt
index 94565c9144..748c2501b8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoModule.kt
@@ -26,8 +26,6 @@ import org.matrix.android.sdk.api.session.crypto.CryptoService
 import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
 import org.matrix.android.sdk.internal.crypto.api.CryptoApi
-import org.matrix.android.sdk.internal.crypto.crosssigning.ComputeTrustTask
-import org.matrix.android.sdk.internal.crypto.crosssigning.DefaultComputeTrustTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.api.RoomKeysApi
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.DefaultCreateKeysBackupVersionTask
@@ -68,7 +66,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.DefaultDownloadKeysForUsers
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultEncryptEventTask
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultGetDeviceInfoTask
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultGetDevicesTask
-import org.matrix.android.sdk.internal.crypto.tasks.DefaultInitializeCrossSigningTask
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendEventTask
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendToDeviceTask
 import org.matrix.android.sdk.internal.crypto.tasks.DefaultSendVerificationMessageTask
@@ -81,7 +78,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
 import org.matrix.android.sdk.internal.crypto.tasks.EncryptEventTask
 import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
 import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
-import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask
 import org.matrix.android.sdk.internal.crypto.tasks.SendEventTask
 import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
 import org.matrix.android.sdk.internal.crypto.tasks.SendVerificationMessageTask
@@ -247,12 +243,6 @@ internal abstract class CryptoModule {
     @Binds
     abstract fun bindCryptoStore(store: RealmCryptoStore): IMXCryptoStore
 
-    @Binds
-    abstract fun bindComputeShieldTrustTask(task: DefaultComputeTrustTask): ComputeTrustTask
-
-    @Binds
-    abstract fun bindInitializeCrossSigningTask(task: DefaultInitializeCrossSigningTask): InitializeCrossSigningTask
-
     @Binds
     abstract fun bindSendEventTask(task: DefaultSendEventTask): SendEventTask
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt
index 082d750cb1..be059888b8 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt
@@ -17,7 +17,7 @@
 package org.matrix.android.sdk.internal.crypto
 
 import com.zhuinden.monarchy.Monarchy
-import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
+import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.internal.database.model.EventEntity
 import org.matrix.android.sdk.internal.database.model.EventEntityFields
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GossipRequestType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DecryptEventUseCase.kt
similarity index 55%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GossipRequestType.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DecryptEventUseCase.kt
index 19f89b2f1e..6eab9dbdae 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GossipRequestType.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DecryptEventUseCase.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright (c) 2022 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.matrix.android.sdk.internal.crypto
 
-interface NewSessionListener {
-    fun onNewSession(roomId: String?, sessionId: String)
+import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
+import org.matrix.android.sdk.api.session.events.model.Event
+import javax.inject.Inject
+
+internal class DecryptEventUseCase @Inject constructor(olmMachineProvider: OlmMachineProvider) {
+
+    private val olmMachine = olmMachineProvider.olmMachine
+
+    suspend operator fun invoke(event: Event): MXEventDecryptionResult {
+        return olmMachine.decryptRoomEvent(event)
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
index 589e0c0e30..2e180de4e7 100755
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt
@@ -138,7 +138,11 @@ internal class DefaultCryptoService @Inject constructor(
         private val keysBackupService: RustKeyBackupService,
         private val megolmSessionImportManager: MegolmSessionImportManager,
         private val olmMachineProvider: OlmMachineProvider,
-        private val liveEventManager: dagger.Lazy<StreamEventsManager>
+        private val liveEventManager: dagger.Lazy<StreamEventsManager>,
+        private val prepareToEncrypt: PrepareToEncryptUseCase,
+        private val encryptEventContent: EncryptEventContentUseCase,
+        private val shouldEncryptForInvitedMembers: ShouldEncryptForInvitedMembersUseCase,
+        private val getRoomUserIds: GetRoomUserIdsUseCase,
 ) : CryptoService {
 
     private val isStarting = AtomicBoolean(false)
@@ -152,14 +156,12 @@ internal class DefaultCryptoService @Inject constructor(
 //    private val deviceObserver: DeviceUpdateObserver = DeviceUpdateObserver()
 
     // Locks for some of our operations
-    private val keyClaimLock: Mutex = Mutex()
     private val outgoingRequestsProcessor = OutgoingRequestsProcessor(
             requestSender = requestSender,
             coroutineScope = cryptoCoroutineScope,
             cryptoSessionInfoProvider = cryptoSessionInfoProvider,
             shieldComputer = crossSigningService::shieldForGroup
     )
-    private val roomKeyShareLocks: ConcurrentHashMap<String, Mutex> = ConcurrentHashMap()
 
     fun onStateEvent(roomId: String, event: Event) {
         when (event.type) {
@@ -450,27 +452,7 @@ internal class DefaultCryptoService @Inject constructor(
     override suspend fun encryptEventContent(eventContent: Content,
                                              eventType: String,
                                              roomId: String): MXEncryptEventContentResult {
-        // moved to crypto scope to have up to date values
-        return withContext(coroutineDispatchers.crypto) {
-            val algorithm = getEncryptionAlgorithm(roomId)
-            if (algorithm != null) {
-                val userIds = getRoomUserIds(roomId)
-                val t0 = System.currentTimeMillis()
-                Timber.tag(loggerTag.value).v("encryptEventContent() starts")
-                measureTimeMillis {
-                    preshareRoomKey(roomId, userIds)
-                }.also {
-                    Timber.d("Shared room key in room $roomId took $it ms")
-                }
-                val content = encrypt(roomId, eventType, eventContent)
-                Timber.tag(loggerTag.value).v("## CRYPTO | encryptEventContent() : succeeds after ${System.currentTimeMillis() - t0} ms")
-                MXEncryptEventContentResult(content, EventType.ENCRYPTED)
-            } else {
-                val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
-                Timber.tag(loggerTag.value).e("encryptEventContent() : failed $reason")
-                throw Failure.CryptoError(MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_ENCRYPT, reason))
-            }
-        }
+        return encryptEventContent.invoke(eventContent, eventType, roomId)
     }
 
     override fun discardOutboundSession(roomId: String) {
@@ -523,12 +505,6 @@ internal class DefaultCryptoService @Inject constructor(
         }
     }
 
-    private fun getRoomUserIds(roomId: String): List<String> {
-        val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser() &&
-                shouldEncryptForInvitedMembers(roomId)
-        return cryptoSessionInfoProvider.getRoomUserIds(roomId, encryptForInvitedMembers)
-    }
-
     /**
      * Handle a change in the membership state of a member of a room.
      *
@@ -593,7 +569,7 @@ internal class DefaultCryptoService @Inject constructor(
                 when (event.type) {
                     EventType.ROOM_KEY           -> {
                         val content = event.getClearContent().toModel<RoomKeyContent>() ?: return@forEach
-
+                        content.sessionKey
                         val roomId = content.sessionId ?: return@forEach
                         val sessionId = content.sessionId
 
@@ -622,80 +598,7 @@ internal class DefaultCryptoService @Inject constructor(
         }
     }
 
-    private suspend fun preshareRoomKey(roomId: String, roomMembers: List<String>) {
-        claimMissingKeys(roomMembers)
-        val keyShareLock = roomKeyShareLocks.getOrPut(roomId) { Mutex() }
-        var sharedKey = false
-        keyShareLock.withLock {
-            coroutineScope {
-                olmMachine.shareRoomKey(roomId, roomMembers).map {
-                    when (it) {
-                        is Request.ToDevice -> {
-                            sharedKey = true
-                            async {
-                                sendToDevice(it)
-                            }
-                        }
-                        else                -> {
-                            // This request can only be a to-device request but
-                            // we need to handle all our cases and put this
-                            // async block for our joinAll to work.
-                            async {}
-                        }
-                    }
-                }.joinAll()
-            }
-        }
 
-        // If we sent out a room key over to-device messages it's likely that we created a new one
-        // Try to back the key up
-        if (sharedKey) {
-            keysBackupService.maybeBackupKeys()
-        }
-    }
-
-    private suspend fun claimMissingKeys(roomMembers: List<String>) = keyClaimLock.withLock {
-        val request = this.olmMachine.getMissingSessions(roomMembers)
-        // This request can only be a keys claim request.
-        when (request) {
-            is Request.KeysClaim -> {
-                claimKeys(request)
-            }
-            else                 -> {
-            }
-        }
-    }
-
-    private suspend fun encrypt(roomId: String, eventType: String, content: Content): Content {
-        return olmMachine.encrypt(roomId, eventType, content)
-    }
-
-    private suspend fun uploadKeys(request: Request.KeysUpload) {
-        try {
-            val response = requestSender.uploadKeys(request)
-            olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_UPLOAD, response)
-        } catch (throwable: Throwable) {
-            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO uploadKeys(): error")
-        }
-    }
-
-    private suspend fun queryKeys(request: Request.KeysQuery) {
-        try {
-            val response = requestSender.queryKeys(request)
-            olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response)
-
-            // Update the shields!
-            cryptoCoroutineScope.launch {
-                cryptoSessionInfoProvider.getRoomsWhereUsersAreParticipating(request.users).forEach { roomId ->
-                    val userGroup = cryptoSessionInfoProvider.getUserListForShieldComputation(roomId)
-                    val shield = crossSigningService.shieldForGroup(userGroup)
-                    cryptoSessionInfoProvider.updateShieldForRoom(roomId, shield)
-                }
-            }
-        } catch (throwable: Throwable) {
-            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO doKeyDownloadForUsers(): error")
-        }
-    }
 
     private suspend fun sendToDevice(request: Request.ToDevice) {
         try {
@@ -706,34 +609,6 @@ internal class DefaultCryptoService @Inject constructor(
         }
     }
 
-    private suspend fun claimKeys(request: Request.KeysClaim) {
-        try {
-            val response = requestSender.claimKeys(request)
-            olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response)
-        } catch (throwable: Throwable) {
-            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO claimKeys(): error")
-        }
-    }
-
-    private suspend fun signatureUpload(request: Request.SignatureUpload) {
-        try {
-            val response = requestSender.sendSignatureUpload(request)
-            olmMachine.markRequestAsSent(request.requestId, RequestType.SIGNATURE_UPLOAD, response)
-        } catch (throwable: Throwable) {
-            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO signatureUpload(): error")
-        }
-    }
-
-    private suspend fun sendRoomMessage(request: Request.RoomMessage) {
-        try {
-            Timber.v("SendRoomMessage: $request")
-            val response = requestSender.sendRoomMessage(request)
-            olmMachine.markRequestAsSent(request.requestId, RequestType.ROOM_MESSAGE, response)
-        } catch (throwable: Throwable) {
-            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO sendRoomMessage(): error")
-        }
-    }
-
     /**
      * Export the crypto keys
      *
@@ -966,32 +841,7 @@ internal class DefaultCryptoService @Inject constructor(
         cryptoStore.logDbUsageInfo()
     }
 
-    override suspend fun prepareToEncrypt(roomId: String) {
-        withContext(coroutineDispatchers.crypto) {
-            Timber.tag(loggerTag.value).d("prepareToEncrypt() roomId:$roomId Check room members up to date")
-            // Ensure to load all room members
-            try {
-                loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
-            } catch (failure: Throwable) {
-                Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to load room members")
-                throw failure
-            }
-            val userIds = getRoomUserIds(roomId)
-
-            val algorithm = getEncryptionAlgorithm(roomId)
-
-            if (algorithm == null) {
-                val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
-                Timber.tag(loggerTag.value).e("prepareToEncrypt() : $reason")
-                throw IllegalArgumentException("Missing algorithm")
-            }
-            try {
-                preshareRoomKey(roomId, userIds)
-            } catch (failure: Throwable) {
-                Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to PreshareRoomKey")
-            }
-        }
-    }
+    override suspend fun prepareToEncrypt(roomId: String) = prepareToEncrypt.invoke(roomId, ensureAllMembersAreLoaded = true)
 
     /* ==========================================================================================
      * For test only
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt
index 8f3491bf0a..90bf533d58 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/Device.kt
@@ -18,11 +18,11 @@ package org.matrix.android.sdk.internal.crypto
 
 import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
+import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
+import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
-import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.internal.crypto.model.rest.UnsignedDeviceInfo
 import org.matrix.android.sdk.internal.crypto.network.RequestSender
 import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
 import uniffi.olm.CryptoStoreException
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
deleted file mode 100755
index db7edc8aa0..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.launch
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.MatrixPatterns
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.internal.crypto.model.CryptoInfoMapper
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.util.logLimit
-import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
-import javax.inject.Inject
-
-// Legacy name: MXDeviceList
-@Deprecated("In favor of rust olmMachine")
-@SessionScope
-internal class DeviceListManager @Inject constructor(
-        private val cryptoStore: IMXCryptoStore,
-        private val olmDevice: MXOlmDevice,
-        private val syncTokenStore: SyncTokenStore,
-        private val credentials: Credentials,
-        private val downloadKeysForUsersTask: DownloadKeysForUsersTask,
-        private val cryptoSessionInfoProvider: CryptoSessionInfoProvider,
-        coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val taskExecutor: TaskExecutor,
-        private val clock: Clock,
-) {
-
-    interface UserDevicesUpdateListener {
-        fun onUsersDeviceUpdate(userIds: List<String>)
-    }
-
-    private val deviceChangeListeners = mutableListOf<UserDevicesUpdateListener>()
-
-    fun addListener(listener: UserDevicesUpdateListener) {
-        synchronized(deviceChangeListeners) {
-            deviceChangeListeners.add(listener)
-        }
-    }
-
-    fun removeListener(listener: UserDevicesUpdateListener) {
-        synchronized(deviceChangeListeners) {
-            deviceChangeListeners.remove(listener)
-        }
-    }
-
-    private fun dispatchDeviceChange(users: List<String>) {
-        synchronized(deviceChangeListeners) {
-            deviceChangeListeners.forEach {
-                try {
-                    it.onUsersDeviceUpdate(users)
-                } catch (failure: Throwable) {
-                    Timber.e(failure, "Failed to dispatch device change")
-                }
-            }
-        }
-    }
-
-    // HS not ready for retry
-    private val notReadyToRetryHS = mutableSetOf<String>()
-
-    private val cryptoCoroutineContext = coroutineDispatchers.crypto
-
-    init {
-        taskExecutor.executorScope.launch(cryptoCoroutineContext) {
-            var isUpdated = false
-            val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
-            for ((userId, status) in deviceTrackingStatuses) {
-                if (TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == status || TRACKING_STATUS_UNREACHABLE_SERVER == status) {
-                    // if a download was in progress when we got shut down, it isn't any more.
-                    deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
-                    isUpdated = true
-                }
-            }
-            if (isUpdated) {
-                cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
-            }
-        }
-    }
-
-    /**
-     * Tells if the key downloads should be tried
-     *
-     * @param userId the userId
-     * @return true if the keys download can be retrieved
-     */
-    private fun canRetryKeysDownload(userId: String): Boolean {
-        var res = false
-
-        if (':' in userId) {
-            try {
-                synchronized(notReadyToRetryHS) {
-                    res = !notReadyToRetryHS.contains(userId.substringAfter(':'))
-                }
-            } catch (e: Exception) {
-                Timber.e(e, "## CRYPTO | canRetryKeysDownload() failed")
-            }
-        }
-
-        return res
-    }
-
-    /**
-     * Clear the unavailable server lists
-     */
-    private fun clearUnavailableServersList() {
-        synchronized(notReadyToRetryHS) {
-            notReadyToRetryHS.clear()
-        }
-    }
-
-    fun onRoomMembersLoadedFor(roomId: String) {
-        taskExecutor.executorScope.launch(cryptoCoroutineContext) {
-            if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) {
-                // It's OK to track also device for invited users
-                val userIds = cryptoSessionInfoProvider.getRoomUserIds(roomId, true)
-                startTrackingDeviceList(userIds)
-                refreshOutdatedDeviceLists()
-            }
-        }
-    }
-
-    /**
-     * Mark the cached device list for the given user outdated
-     * flag the given user for device-list tracking, if they are not already.
-     *
-     * @param userIds the user ids list
-     */
-    fun startTrackingDeviceList(userIds: List<String>) {
-        var isUpdated = false
-        val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
-
-        for (userId in userIds) {
-            if (!deviceTrackingStatuses.containsKey(userId) || TRACKING_STATUS_NOT_TRACKED == deviceTrackingStatuses[userId]) {
-                Timber.v("## CRYPTO | startTrackingDeviceList() : Now tracking device list for $userId")
-                deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
-                isUpdated = true
-            }
-        }
-
-        if (isUpdated) {
-            cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
-        }
-    }
-
-    /**
-     * Update the devices list statuses
-     *
-     * @param changed the user ids list which have new devices
-     * @param left    the user ids list which left a room
-     */
-    fun handleDeviceListsChanges(changed: Collection<String>, left: Collection<String>) {
-        Timber.v("## CRYPTO: handleDeviceListsChanges changed: ${changed.logLimit()} / left: ${left.logLimit()}")
-        var isUpdated = false
-        val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
-
-        if (changed.isNotEmpty() || left.isNotEmpty()) {
-            clearUnavailableServersList()
-        }
-
-        for (userId in changed) {
-            if (deviceTrackingStatuses.containsKey(userId)) {
-                Timber.v("## CRYPTO | handleDeviceListsChanges() : Marking device list outdated for $userId")
-                deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
-                isUpdated = true
-            }
-        }
-
-        for (userId in left) {
-            if (deviceTrackingStatuses.containsKey(userId)) {
-                Timber.v("## CRYPTO | handleDeviceListsChanges() : No longer tracking device list for $userId")
-                deviceTrackingStatuses[userId] = TRACKING_STATUS_NOT_TRACKED
-                isUpdated = true
-            }
-        }
-
-        if (isUpdated) {
-            cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
-        }
-    }
-
-    /**
-     * This will flag each user whose devices we are tracking as in need of an
-     * + update
-     */
-    fun invalidateAllDeviceLists() {
-        handleDeviceListsChanges(cryptoStore.getDeviceTrackingStatuses().keys, emptyList())
-    }
-
-    /**
-     * The keys download failed
-     *
-     * @param userIds the user ids list
-     */
-    private fun onKeysDownloadFailed(userIds: List<String>) {
-        val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
-        userIds.associateWithTo(deviceTrackingStatuses) { TRACKING_STATUS_PENDING_DOWNLOAD }
-        cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
-    }
-
-    /**
-     * The keys download succeeded.
-     *
-     * @param userIds  the userIds list
-     * @param failures the failure map.
-     */
-    private fun onKeysDownloadSucceed(userIds: List<String>, failures: Map<String, Map<String, Any>>?): MXUsersDevicesMap<CryptoDeviceInfo> {
-        if (failures != null) {
-            for ((k, value) in failures) {
-                val statusCode = when (val status = value["status"]) {
-                    is Double -> status.toInt()
-                    is Int    -> status.toInt()
-                    else      -> 0
-                }
-                if (statusCode == 503) {
-                    synchronized(notReadyToRetryHS) {
-                        notReadyToRetryHS.add(k)
-                    }
-                }
-            }
-        }
-        val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
-        val usersDevicesInfoMap = MXUsersDevicesMap<CryptoDeviceInfo>()
-        for (userId in userIds) {
-            val devices = cryptoStore.getUserDevices(userId)
-            if (null == devices) {
-                if (canRetryKeysDownload(userId)) {
-                    deviceTrackingStatuses[userId] = TRACKING_STATUS_PENDING_DOWNLOAD
-                    Timber.e("failed to retry the devices of $userId : retry later")
-                } else {
-                    if (deviceTrackingStatuses.containsKey(userId) && TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses[userId]) {
-                        deviceTrackingStatuses[userId] = TRACKING_STATUS_UNREACHABLE_SERVER
-                        Timber.e("failed to retry the devices of $userId : the HS is not available")
-                    }
-                }
-            } else {
-                if (deviceTrackingStatuses.containsKey(userId) && TRACKING_STATUS_DOWNLOAD_IN_PROGRESS == deviceTrackingStatuses[userId]) {
-                    // we didn't get any new invalidations since this download started:
-                    //  this user's device list is now up to date.
-                    deviceTrackingStatuses[userId] = TRACKING_STATUS_UP_TO_DATE
-                    Timber.v("Device list for $userId now up to date")
-                }
-                // And the response result
-                usersDevicesInfoMap.setObjects(userId, devices)
-            }
-        }
-        cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
-
-        dispatchDeviceChange(userIds)
-        return usersDevicesInfoMap
-    }
-
-    /**
-     * Download the device keys for a list of users and stores the keys in the MXStore.
-     * It must be called in getEncryptingThreadHandler() thread.
-     *
-     * @param userIds       The users to fetch.
-     * @param forceDownload Always download the keys even if cached.
-     */
-    suspend fun downloadKeys(userIds: List<String>?, forceDownload: Boolean): MXUsersDevicesMap<CryptoDeviceInfo> {
-        Timber.v("## CRYPTO | downloadKeys() : forceDownload $forceDownload : $userIds")
-        // Map from userId -> deviceId -> MXDeviceInfo
-        val stored = MXUsersDevicesMap<CryptoDeviceInfo>()
-
-        // List of user ids we need to download keys for
-        val downloadUsers = ArrayList<String>()
-        if (null != userIds) {
-            if (forceDownload) {
-                downloadUsers.addAll(userIds)
-            } else {
-                for (userId in userIds) {
-                    val status = cryptoStore.getDeviceTrackingStatus(userId, TRACKING_STATUS_NOT_TRACKED)
-                    // downloading keys ->the keys download won't be triggered twice but the callback requires the dedicated keys
-                    // not yet retrieved
-                    if (TRACKING_STATUS_UP_TO_DATE != status && TRACKING_STATUS_UNREACHABLE_SERVER != status) {
-                        downloadUsers.add(userId)
-                    } else {
-                        val devices = cryptoStore.getUserDevices(userId)
-                        // should always be true
-                        if (devices != null) {
-                            stored.setObjects(userId, devices)
-                        } else {
-                            downloadUsers.add(userId)
-                        }
-                    }
-                }
-            }
-        }
-        return if (downloadUsers.isEmpty()) {
-            Timber.v("## CRYPTO | downloadKeys() : no new user device")
-            stored
-        } else {
-            Timber.v("## CRYPTO | downloadKeys() : starts")
-            val t0 = clock.epochMillis()
-            try {
-                val result = doKeyDownloadForUsers(downloadUsers)
-                Timber.v("## CRYPTO | downloadKeys() : doKeyDownloadForUsers succeeds after ${clock.epochMillis() - t0} ms")
-                result.also {
-                    it.addEntriesFromMap(stored)
-                }
-            } catch (failure: Throwable) {
-                Timber.w(failure, "## CRYPTO | downloadKeys() : doKeyDownloadForUsers failed after ${clock.epochMillis() - t0} ms")
-                if (forceDownload) {
-                    throw failure
-                } else {
-                    stored
-                }
-            }
-        }
-    }
-
-    /**
-     * Download the devices keys for a set of users.
-     *
-     * @param downloadUsers the user ids list
-     */
-    private suspend fun doKeyDownloadForUsers(downloadUsers: List<String>): MXUsersDevicesMap<CryptoDeviceInfo> {
-        Timber.v("## CRYPTO | doKeyDownloadForUsers() : doKeyDownloadForUsers ${downloadUsers.logLimit()}")
-        // get the user ids which did not already trigger a keys download
-        val filteredUsers = downloadUsers.filter { MatrixPatterns.isUserId(it) }
-        if (filteredUsers.isEmpty()) {
-            // trigger nothing
-            return MXUsersDevicesMap()
-        }
-        val params = DownloadKeysForUsersTask.Params(filteredUsers, syncTokenStore.getLastToken())
-        val response = try {
-            downloadKeysForUsersTask.execute(params)
-        } catch (throwable: Throwable) {
-            Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error")
-            if (throwable is CancellationException) {
-                // the crypto module is getting closed, so we cannot access the DB anymore
-                Timber.w("The crypto module is closed, ignoring this error")
-            } else {
-                onKeysDownloadFailed(filteredUsers)
-            }
-            throw throwable
-        }
-        Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
-        for (userId in filteredUsers) {
-            // al devices =
-            val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
-
-            Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for $userId : $models")
-            if (!models.isNullOrEmpty()) {
-                val workingCopy = models.toMutableMap()
-                for ((deviceId, deviceInfo) in models) {
-                    // Get the potential previously store device keys for this device
-                    val previouslyStoredDeviceKeys = cryptoStore.getUserDevice(userId, deviceId)
-
-                    // in some race conditions (like unit tests)
-                    // the self device must be seen as verified
-                    if (deviceInfo.deviceId == credentials.deviceId && userId == credentials.userId) {
-                        deviceInfo.trustLevel = DeviceTrustLevel(previouslyStoredDeviceKeys?.trustLevel?.crossSigningVerified ?: false, true)
-                    }
-                    // Validate received keys
-                    if (!validateDeviceKeys(deviceInfo, userId, deviceId, previouslyStoredDeviceKeys)) {
-                        // New device keys are not valid. Do not store them
-                        workingCopy.remove(deviceId)
-                        if (null != previouslyStoredDeviceKeys) {
-                            // But keep old validated ones if any
-                            workingCopy[deviceId] = previouslyStoredDeviceKeys
-                        }
-                    } else if (null != previouslyStoredDeviceKeys) {
-                        // The verified status is not sync'ed with hs.
-                        // This is a client side information, valid only for this client.
-                        // So, transfer its previous value
-                        workingCopy[deviceId]!!.trustLevel = previouslyStoredDeviceKeys.trustLevel
-                    }
-                }
-                // Update the store
-                // Note that devices which aren't in the response will be removed from the stores
-                cryptoStore.storeUserDevices(userId, workingCopy)
-            }
-
-            val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
-                Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
-            }
-            val selfSigningKey = response.selfSigningKeys?.get(userId)?.toCryptoModel()?.also {
-                Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : SSK ${it.unpaddedBase64PublicKey}")
-            }
-            val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
-                Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
-            }
-            cryptoStore.storeUserCrossSigningKeys(
-                    userId,
-                    masterKey,
-                    selfSigningKey,
-                    userSigningKey
-            )
-        }
-
-        // Update devices trust for these users
-        // dispatchDeviceChange(downloadUsers)
-
-        return onKeysDownloadSucceed(filteredUsers, response.failures)
-    }
-
-    /**
-     * Validate device keys.
-     * This method must called on getEncryptingThreadHandler() thread.
-     *
-     * @param deviceKeys                 the device keys to validate.
-     * @param userId                     the id of the user of the device.
-     * @param deviceId                   the id of the device.
-     * @param previouslyStoredDeviceKeys the device keys we received before for this device
-     * @return true if succeeds
-     */
-    private fun validateDeviceKeys(deviceKeys: CryptoDeviceInfo?, userId: String, deviceId: String, previouslyStoredDeviceKeys: CryptoDeviceInfo?): Boolean {
-        if (null == deviceKeys) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys is null from $userId:$deviceId")
-            return false
-        }
-
-        if (null == deviceKeys.keys) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.keys is null from $userId:$deviceId")
-            return false
-        }
-
-        if (null == deviceKeys.signatures) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : deviceKeys.signatures is null from $userId:$deviceId")
-            return false
-        }
-
-        // Check that the user_id and device_id in the received deviceKeys are correct
-        if (deviceKeys.userId != userId) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched user_id ${deviceKeys.userId} from $userId:$deviceId")
-            return false
-        }
-
-        if (deviceKeys.deviceId != deviceId) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : Mismatched device_id ${deviceKeys.deviceId} from $userId:$deviceId")
-            return false
-        }
-
-        val signKeyId = "ed25519:" + deviceKeys.deviceId
-        val signKey = deviceKeys.keys[signKeyId]
-
-        if (null == signKey) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no ed25519 key")
-            return false
-        }
-
-        val signatureMap = deviceKeys.signatures[userId]
-
-        if (null == signatureMap) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} has no map for $userId")
-            return false
-        }
-
-        val signature = signatureMap[signKeyId]
-
-        if (null == signature) {
-            Timber.e("## CRYPTO | validateDeviceKeys() : Device $userId:${deviceKeys.deviceId} is not signed")
-            return false
-        }
-
-        var isVerified = false
-        var errorMessage: String? = null
-
-        try {
-            olmDevice.verifySignature(signKey, deviceKeys.signalableJSONDictionary(), signature)
-            isVerified = true
-        } catch (e: Exception) {
-            errorMessage = e.message
-        }
-
-        if (!isVerified) {
-            Timber.e(
-                    "## CRYPTO | validateDeviceKeys() : Unable to verify signature on device " + userId + ":" +
-                            deviceKeys.deviceId + " with error " + errorMessage
-            )
-            return false
-        }
-
-        if (null != previouslyStoredDeviceKeys) {
-            if (previouslyStoredDeviceKeys.fingerprint() != signKey) {
-                // This should only happen if the list has been MITMed; we are
-                // best off sticking with the original keys.
-                //
-                // Should we warn the user about it somehow?
-                Timber.e(
-                        "## CRYPTO | validateDeviceKeys() : WARNING:Ed25519 key for device " + userId + ":" +
-                                deviceKeys.deviceId + " has changed : " +
-                                previouslyStoredDeviceKeys.fingerprint() + " -> " + signKey
-                )
-
-                Timber.e("## CRYPTO | validateDeviceKeys() : $previouslyStoredDeviceKeys -> $deviceKeys")
-                Timber.e("## CRYPTO | validateDeviceKeys() : ${previouslyStoredDeviceKeys.keys} -> ${deviceKeys.keys}")
-
-                return false
-            }
-        }
-
-        return true
-    }
-
-    /**
-     * Start device queries for any users who sent us an m.new_device recently
-     * This method must be called on getEncryptingThreadHandler() thread.
-     */
-    suspend fun refreshOutdatedDeviceLists() {
-        Timber.v("## CRYPTO | refreshOutdatedDeviceLists()")
-        val deviceTrackingStatuses = cryptoStore.getDeviceTrackingStatuses().toMutableMap()
-
-        val users = deviceTrackingStatuses.keys.filterTo(mutableListOf()) { userId ->
-            TRACKING_STATUS_PENDING_DOWNLOAD == deviceTrackingStatuses[userId]
-        }
-
-        if (users.isEmpty()) {
-            return
-        }
-
-        // update the statuses
-        users.associateWithTo(deviceTrackingStatuses) { TRACKING_STATUS_DOWNLOAD_IN_PROGRESS }
-
-        cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
-        runCatching {
-            doKeyDownloadForUsers(users)
-        }.fold(
-                {
-                    Timber.v("## CRYPTO | refreshOutdatedDeviceLists() : done")
-                },
-                {
-                    Timber.e(it, "## CRYPTO | refreshOutdatedDeviceLists() : ERROR updating device keys for users $users")
-                }
-        )
-    }
-
-    companion object {
-
-        /**
-         * State transition diagram for DeviceList.deviceTrackingStatus
-         * <pre>
-         *
-         *                                   |
-         *        stopTrackingDeviceList     V
-         *      +---------------------> NOT_TRACKED
-         *      |                            |
-         *      +<--------------------+      | startTrackingDeviceList
-         *      |                     |      V
-         *      |   +-------------> PENDING_DOWNLOAD <--------------------+-+
-         *      |   |                      ^ |                            | |
-         *      |   | restart     download | |  start download            | | invalidateUserDeviceList
-         *      |   | client        failed | |                            | |
-         *      |   |                      | V                            | |
-         *      |   +------------ DOWNLOAD_IN_PROGRESS -------------------+ |
-         *      |                    |       |                              |
-         *      +<-------------------+       |  download successful         |
-         *      ^                            V                              |
-         *      +----------------------- UP_TO_DATE ------------------------+
-         *
-         * </pre>
-         */
-
-        const val TRACKING_STATUS_NOT_TRACKED = -1
-        const val TRACKING_STATUS_PENDING_DOWNLOAD = 1
-        const val TRACKING_STATUS_DOWNLOAD_IN_PROGRESS = 2
-        const val TRACKING_STATUS_UP_TO_DATE = 3
-        const val TRACKING_STATUS_UNREACHABLE_SERVER = 4
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EncryptEventContentUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EncryptEventContentUseCase.kt
new file mode 100644
index 0000000000..db5168d31c
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EncryptEventContentUseCase.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto
+
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.model.MXEncryptEventContentResult
+import org.matrix.android.sdk.api.session.events.model.Content
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.internal.util.time.Clock
+import timber.log.Timber
+import javax.inject.Inject
+
+private val loggerTag = LoggerTag("EncryptEventContentUseCase", LoggerTag.CRYPTO)
+
+internal class EncryptEventContentUseCase @Inject constructor(olmMachineProvider: OlmMachineProvider,
+                                                              private val prepareToEncrypt: PrepareToEncryptUseCase,
+                                                              private val clock: Clock) {
+
+    private val olmMachine = olmMachineProvider.olmMachine
+
+    suspend operator fun invoke(eventContent: Content,
+                                eventType: String,
+                                roomId: String): MXEncryptEventContentResult {
+        val t0 = clock.epochMillis()
+        prepareToEncrypt(roomId, ensureAllMembersAreLoaded = false)
+        val content = olmMachine.encrypt(roomId, eventType, eventContent)
+        Timber.tag(loggerTag.value).v("## CRYPTO | encryptEventContent() : succeeds after ${clock.epochMillis() - t0} ms")
+        return MXEncryptEventContentResult(content, EventType.ENCRYPTED)
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
deleted file mode 100644
index a094189645..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_OLM
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.OlmEventContent
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.extensions.foldToCallback
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
-import javax.inject.Inject
-
-private const val SEND_TO_DEVICE_RETRY_COUNT = 3
-
-private val loggerTag = LoggerTag("CryptoSyncHandler", LoggerTag.CRYPTO)
-
-@SessionScope
-internal class EventDecryptor @Inject constructor(
-        private val cryptoCoroutineScope: CoroutineScope,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val clock: Clock,
-        private val roomDecryptorProvider: RoomDecryptorProvider,
-        private val messageEncrypter: MessageEncrypter,
-        private val sendToDeviceTask: SendToDeviceTask,
-        private val deviceListManager: DeviceListManager,
-        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
-        private val cryptoStore: IMXCryptoStore
-) {
-
-    /**
-     * Rate limit unwedge attempt, should we persist that?
-     */
-    private val lastNewSessionForcedDates = mutableMapOf<WedgedDeviceInfo, Long>()
-
-    data class WedgedDeviceInfo(
-            val userId: String,
-            val senderKey: String?
-    )
-
-    private val wedgedDevices = mutableListOf<WedgedDeviceInfo>()
-
-    /**
-     * Decrypt an event
-     *
-     * @param event    the raw event.
-     * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
-     * @return the MXEventDecryptionResult data, or throw in case of error
-     */
-    @Throws(MXCryptoError::class)
-    suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
-        return internalDecryptEvent(event, timeline)
-    }
-
-    /**
-     * Decrypt an event asynchronously
-     *
-     * @param event    the raw event.
-     * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
-     * @param callback the callback to return data or null
-     */
-    fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>) {
-        // is it needed to do that on the crypto scope??
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            runCatching {
-                internalDecryptEvent(event, timeline)
-            }.foldToCallback(callback)
-        }
-    }
-
-    /**
-     * Decrypt an event
-     *
-     * @param event    the raw event.
-     * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
-     * @return the MXEventDecryptionResult data, or null in case of error
-     */
-    @Throws(MXCryptoError::class)
-    private suspend fun internalDecryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
-        val eventContent = event.content
-        if (eventContent == null) {
-            Timber.tag(loggerTag.value).e("decryptEvent : empty event content")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
-        } else {
-            val algorithm = eventContent["algorithm"]?.toString()
-            val alg = roomDecryptorProvider.getOrCreateRoomDecryptor(event.roomId, algorithm)
-            if (alg == null) {
-                val reason = String.format(MXCryptoError.UNABLE_TO_DECRYPT_REASON, event.eventId, algorithm)
-                Timber.tag(loggerTag.value).e("decryptEvent() : $reason")
-                throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, reason)
-            } else {
-                try {
-                    return alg.decryptEvent(event, timeline)
-                } catch (mxCryptoError: MXCryptoError) {
-                    Timber.tag(loggerTag.value).d("internalDecryptEvent : Failed to decrypt ${event.eventId} reason: $mxCryptoError")
-                    if (algorithm == MXCRYPTO_ALGORITHM_OLM) {
-                        if (mxCryptoError is MXCryptoError.Base &&
-                                mxCryptoError.errorType == MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE) {
-                            // need to find sending device
-                            val olmContent = event.content.toModel<OlmEventContent>()
-                            if (event.senderId != null && olmContent?.senderKey != null) {
-                                markOlmSessionForUnwedging(event.senderId, olmContent.senderKey)
-                            } else {
-                                Timber.tag(loggerTag.value).d("Can't mark as wedge malformed")
-                            }
-                        }
-                    }
-                    throw mxCryptoError
-                }
-            }
-        }
-    }
-
-    private fun markOlmSessionForUnwedging(senderId: String, senderKey: String) {
-        val info = WedgedDeviceInfo(senderId, senderKey)
-        if (!wedgedDevices.contains(info)) {
-            Timber.tag(loggerTag.value).d("Marking device from $senderId key:$senderKey as wedged")
-            wedgedDevices.add(info)
-        }
-    }
-
-    // coroutineDispatchers.crypto scope
-    suspend fun unwedgeDevicesIfNeeded() {
-        // handle wedged devices
-        // Some olm decryption have failed and some device are wedged
-        // we should force start a new session for those
-        Timber.tag(loggerTag.value).v("Unwedging:  ${wedgedDevices.size} are wedged")
-        // get the one that should be retried according to rate limit
-        val now = clock.epochMillis()
-        val toUnwedge = wedgedDevices.filter {
-            val lastForcedDate = lastNewSessionForcedDates[it] ?: 0
-            if (now - lastForcedDate < DefaultCryptoService.CRYPTO_MIN_FORCE_SESSION_PERIOD_MILLIS) {
-                Timber.tag(loggerTag.value).d("Unwedging, New session for $it already forced with device at $lastForcedDate")
-                return@filter false
-            }
-            // let's already mark that we tried now
-            lastNewSessionForcedDates[it] = now
-            true
-        }
-
-        if (toUnwedge.isEmpty()) {
-            Timber.tag(loggerTag.value).v("Nothing to unwedge")
-            return
-        }
-        Timber.tag(loggerTag.value).d("Unwedging, trying to create new session for ${toUnwedge.size} devices")
-
-        toUnwedge
-                .chunked(100) // safer to chunk if we ever have lots of wedged devices
-                .forEach { wedgedList ->
-                    val groupedByUserId = wedgedList.groupBy { it.userId }
-                    // lets download keys if needed
-                    withContext(coroutineDispatchers.io) {
-                        deviceListManager.downloadKeys(groupedByUserId.keys.toList(), false)
-                    }
-
-                    // find the matching devices
-                    groupedByUserId
-                            .map { groupedByUser ->
-                                val userId = groupedByUser.key
-                                val wedgeSenderKeysForUser = groupedByUser.value.map { it.senderKey }
-                                val knownDevices = cryptoStore.getUserDevices(userId)?.values.orEmpty()
-                                userId to wedgeSenderKeysForUser.mapNotNull { senderKey ->
-                                    knownDevices.firstOrNull { it.identityKey() == senderKey }
-                                }
-                            }
-                            .toMap()
-                            .let { deviceList ->
-                                try {
-                                    // force creating new outbound session and mark them as most recent to
-                                    // be used for next encryption (dummy)
-                                    val sessionToUse = ensureOlmSessionsForDevicesAction.handle(deviceList, true)
-                                    Timber.tag(loggerTag.value).d("Unwedging, found ${sessionToUse.map.size} to send dummy to")
-
-                                    // Now send a dummy message on that session so the other side knows about it.
-                                    val payloadJson = mapOf(
-                                            "type" to EventType.DUMMY
-                                    )
-                                    val sendToDeviceMap = MXUsersDevicesMap<Any>()
-                                    sessionToUse.map.values
-                                            .flatMap { it.values }
-                                            .map { it.deviceInfo }
-                                            .forEach { deviceInfo ->
-                                                Timber.tag(loggerTag.value).v("encrypting dummy to ${deviceInfo.deviceId}")
-                                                val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
-                                                sendToDeviceMap.setObject(deviceInfo.userId, deviceInfo.deviceId, encodedPayload)
-                                            }
-
-                                    // now let's send that
-                                    val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-                                    withContext(coroutineDispatchers.io) {
-                                        sendToDeviceTask.executeRetry(sendToDeviceParams, remainingRetry = SEND_TO_DEVICE_RETRY_COUNT)
-                                    }
-                                } catch (failure: Throwable) {
-                                    deviceList.flatMap { it.value }.joinToString { it.shortDebugString() }.let {
-                                        Timber.tag(loggerTag.value).e(failure, "## Failed to unwedge devices: $it}")
-                                    }
-                                }
-                            }
-                }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GetRoomUserIdsUseCase.kt
similarity index 52%
rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt
rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GetRoomUserIdsUseCase.kt
index d5c5e85e41..75d3e8b0bb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryptionFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/GetRoomUserIdsUseCase.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
+ * Copyright (c) 2022 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,19 +14,14 @@
  * limitations under the License.
  */
 
-package org.matrix.android.sdk.internal.crypto.algorithms.olm
+package org.matrix.android.sdk.internal.crypto
 
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.di.UserId
 import javax.inject.Inject
 
-internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                          @UserId private val userId: String) {
+internal class GetRoomUserIdsUseCase @Inject constructor(private val shouldEncryptForInvitedMembers: ShouldEncryptForInvitedMembersUseCase,
+                                                         private val cryptoSessionInfoProvider: CryptoSessionInfoProvider) {
 
-    fun create(): MXOlmDecryption {
-        return MXOlmDecryption(
-                olmDevice,
-                userId
-        )
+    operator fun invoke(roomId: String): List<String> {
+        return cryptoSessionInfoProvider.getRoomUserIds(roomId, shouldEncryptForInvitedMembers(roomId))
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
deleted file mode 100644
index 13f2fb861a..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingKeyRequestManager.kt
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright 2022 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.withLock
-import kotlinx.coroutines.withContext
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
-import org.matrix.android.sdk.api.crypto.MXCryptoConfig
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.IncomingRoomKeyRequest
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyShareRequest
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
-import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
-import java.util.concurrent.Executors
-import javax.inject.Inject
-import kotlin.system.measureTimeMillis
-
-private val loggerTag = LoggerTag("IncomingKeyRequestManager", LoggerTag.CRYPTO)
-
-@SessionScope
-internal class IncomingKeyRequestManager @Inject constructor(
-        private val credentials: Credentials,
-        private val cryptoStore: IMXCryptoStore,
-        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
-        private val olmDevice: MXOlmDevice,
-        private val cryptoConfig: MXCryptoConfig,
-        private val messageEncrypter: MessageEncrypter,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val sendToDeviceTask: SendToDeviceTask,
-        private val clock: Clock,
-) {
-
-    private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
-    private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
-    val sequencer = SemaphoreCoroutineSequencer()
-
-    private val incomingRequestBuffer = mutableListOf<ValidMegolmRequestBody>()
-
-    // the listeners
-    private val gossipingRequestListeners: MutableSet<GossipingRequestListener> = HashSet()
-
-    enum class MegolmRequestAction {
-        Request, Cancel
-    }
-
-    data class ValidMegolmRequestBody(
-            val requestId: String,
-            val requestingUserId: String,
-            val requestingDeviceId: String,
-            val roomId: String,
-            val senderKey: String,
-            val sessionId: String,
-            val action: MegolmRequestAction
-    ) {
-        fun shortDbgString() = "Request from $requestingUserId|$requestingDeviceId for session $sessionId in room $roomId"
-    }
-
-    private fun RoomKeyShareRequest.toValidMegolmRequest(senderId: String): ValidMegolmRequestBody? {
-        val deviceId = requestingDeviceId ?: return null
-        val body = body ?: return null
-        val roomId = body.roomId ?: return null
-        val sessionId = body.sessionId ?: return null
-        val senderKey = body.senderKey ?: return null
-        val requestId = this.requestId ?: return null
-        if (body.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
-        val action = when (this.action) {
-            "request" -> MegolmRequestAction.Request
-            "request_cancellation" -> MegolmRequestAction.Cancel
-            else -> null
-        } ?: return null
-        return ValidMegolmRequestBody(
-                requestId = requestId,
-                requestingUserId = senderId,
-                requestingDeviceId = deviceId,
-                roomId = roomId,
-                senderKey = senderKey,
-                sessionId = sessionId,
-                action = action
-        )
-    }
-
-    fun addNewIncomingRequest(senderId: String, request: RoomKeyShareRequest) {
-        if (!cryptoStore.isKeyGossipingEnabled()) {
-            Timber.tag(loggerTag.value)
-                    .i("Ignore incoming key request as per crypto config in room ${request.body?.roomId}")
-            return
-        }
-        outgoingRequestScope.launch {
-            // It is important to handle requests in order
-            sequencer.post {
-                val validMegolmRequest = request.toValidMegolmRequest(senderId) ?: return@post Unit.also {
-                    Timber.tag(loggerTag.value).w("Received key request for unknown algorithm ${request.body?.algorithm}")
-                }
-
-                // is there already one like that?
-                val existing = incomingRequestBuffer.firstOrNull { it == validMegolmRequest }
-                if (existing == null) {
-                    when (validMegolmRequest.action) {
-                        MegolmRequestAction.Request -> {
-                            // just add to the buffer
-                            incomingRequestBuffer.add(validMegolmRequest)
-                        }
-                        MegolmRequestAction.Cancel  -> {
-                            // ignore, we can't cancel as it's not known (probably already processed)
-                            // still notify app layer if it was passed up previously
-                            IncomingRoomKeyRequest.fromRestRequest(senderId, request, clock)?.let { iReq ->
-                                outgoingRequestScope.launch(coroutineDispatchers.computation) {
-                                    val listenersCopy = synchronized(gossipingRequestListeners) {
-                                        gossipingRequestListeners.toList()
-                                    }
-                                    listenersCopy.onEach {
-                                        tryOrNull {
-                                            withContext(coroutineDispatchers.main) {
-                                                it.onRequestCancelled(iReq)
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                } else {
-                    when (validMegolmRequest.action) {
-                        MegolmRequestAction.Request -> {
-                            // it's already in buffer, nop keep existing
-                        }
-                        MegolmRequestAction.Cancel  -> {
-                            // discard the request in buffer
-                            incomingRequestBuffer.remove(existing)
-                            outgoingRequestScope.launch(coroutineDispatchers.computation) {
-                                val listenersCopy = synchronized(gossipingRequestListeners) {
-                                    gossipingRequestListeners.toList()
-                                }
-                                listenersCopy.onEach {
-                                    IncomingRoomKeyRequest.fromRestRequest(senderId, request, clock)?.let { iReq ->
-                                        withContext(coroutineDispatchers.main) {
-                                            tryOrNull { it.onRequestCancelled(iReq) }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    fun processIncomingRequests() {
-        outgoingRequestScope.launch {
-            sequencer.post {
-                measureTimeMillis {
-                    Timber.tag(loggerTag.value).v("processIncomingKeyRequests : ${incomingRequestBuffer.size} request to process")
-                    incomingRequestBuffer.forEach {
-                        // should not happen, we only store requests
-                        if (it.action != MegolmRequestAction.Request) return@forEach
-                        try {
-                            handleIncomingRequest(it)
-                        } catch (failure: Throwable) {
-                            // ignore and continue, should not happen
-                            Timber.tag(loggerTag.value).w(failure, "processIncomingKeyRequests : failed to process request $it")
-                        }
-                    }
-                    incomingRequestBuffer.clear()
-                }.let { duration ->
-                    Timber.tag(loggerTag.value).v("Finish processing incoming key request in $duration ms")
-                }
-            }
-        }
-    }
-
-    private suspend fun handleIncomingRequest(request: ValidMegolmRequestBody) {
-        // We don't want to download keys, if we don't know the device yet we won't share any how?
-        val requestingDevice =
-                cryptoStore.getUserDevice(request.requestingUserId, request.requestingDeviceId)
-                        ?: return Unit.also {
-                            Timber.tag(loggerTag.value).d("Ignoring key request: ${request.shortDbgString()}")
-                        }
-
-        cryptoStore.saveIncomingKeyRequestAuditTrail(
-                request.requestId,
-                request.roomId,
-                request.sessionId,
-                request.senderKey,
-                MXCRYPTO_ALGORITHM_MEGOLM,
-                request.requestingUserId,
-                request.requestingDeviceId
-        )
-
-        val roomAlgorithm = // withContext(coroutineDispatchers.crypto) {
-                cryptoStore.getRoomAlgorithm(request.roomId)
-//        }
-        if (roomAlgorithm != MXCRYPTO_ALGORITHM_MEGOLM) {
-            // strange we received a request for a room that is not encrypted
-            // maybe a broken state?
-            Timber.tag(loggerTag.value).w("Received a key request in a room with unsupported alg:$roomAlgorithm , req:${request.shortDbgString()}")
-            return
-        }
-
-        // Is it for one of our sessions?
-        if (request.requestingUserId == credentials.userId) {
-            Timber.tag(loggerTag.value).v("handling request from own user: megolm session ${request.sessionId}")
-
-            if (request.requestingDeviceId == credentials.deviceId) {
-                // ignore it's a remote echo
-                return
-            }
-            // If it's verified we share from the early index we know
-            // if not we check if it was originaly shared or not
-            if (requestingDevice.isVerified) {
-                // we share from the earliest known chain index
-                shareMegolmKey(request, requestingDevice, null)
-            } else {
-                shareIfItWasPreviouslyShared(request, requestingDevice)
-            }
-        } else {
-            if (cryptoConfig.limitRoomKeyRequestsToMyDevices) {
-                Timber.tag(loggerTag.value).v("Ignore request from other user as per crypto config: ${request.shortDbgString()}")
-                return
-            }
-            Timber.tag(loggerTag.value).v("handling request from other user: megolm session ${request.sessionId}")
-            if (requestingDevice.isBlocked) {
-                // it's blocked, so send a withheld code
-                sendWithheldForRequest(request, WithHeldCode.BLACKLISTED)
-            } else {
-                shareIfItWasPreviouslyShared(request, requestingDevice)
-            }
-        }
-    }
-
-    private suspend fun shareIfItWasPreviouslyShared(request: ValidMegolmRequestBody, requestingDevice: CryptoDeviceInfo) {
-        // we don't reshare unless it was previously shared with
-        val wasSessionSharedWithUser = withContext(coroutineDispatchers.crypto) {
-            cryptoStore.getSharedSessionInfo(request.roomId, request.sessionId, requestingDevice)
-        }
-        if (wasSessionSharedWithUser.found && wasSessionSharedWithUser.chainIndex != null) {
-            // we share from the index it was previously shared with
-            shareMegolmKey(request, requestingDevice, wasSessionSharedWithUser.chainIndex.toLong())
-        } else {
-            val isOwnDevice = requestingDevice.userId == credentials.userId
-            sendWithheldForRequest(request, if (isOwnDevice) WithHeldCode.UNVERIFIED else WithHeldCode.UNAUTHORISED)
-            // if it's our device we could delegate to the app layer to decide
-            if (isOwnDevice) {
-                outgoingRequestScope.launch(coroutineDispatchers.computation) {
-                    val listenersCopy = synchronized(gossipingRequestListeners) {
-                        gossipingRequestListeners.toList()
-                    }
-                    val iReq = IncomingRoomKeyRequest(
-                            userId = requestingDevice.userId,
-                            deviceId = requestingDevice.deviceId,
-                            requestId = request.requestId,
-                            requestBody = RoomKeyRequestBody(
-                                    algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
-                                    senderKey = request.senderKey,
-                                    sessionId = request.sessionId,
-                                    roomId = request.roomId
-                            ),
-                            localCreationTimestamp = clock.epochMillis()
-                    )
-                    listenersCopy.onEach {
-                        withContext(coroutineDispatchers.main) {
-                            tryOrNull { it.onRoomKeyRequest(iReq) }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private suspend fun sendWithheldForRequest(request: ValidMegolmRequestBody, code: WithHeldCode) {
-        Timber.tag(loggerTag.value)
-                .w("Send withheld $code for req: ${request.shortDbgString()}")
-        val withHeldContent = RoomKeyWithHeldContent(
-                roomId = request.roomId,
-                senderKey = request.senderKey,
-                algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
-                sessionId = request.sessionId,
-                codeString = code.value,
-                fromDevice = credentials.deviceId
-        )
-
-        val params = SendToDeviceTask.Params(
-                EventType.ROOM_KEY_WITHHELD,
-                MXUsersDevicesMap<Any>().apply {
-                    setObject(request.requestingUserId, request.requestingDeviceId, withHeldContent)
-                }
-        )
-        try {
-            withContext(coroutineDispatchers.io) {
-                sendToDeviceTask.execute(params)
-                Timber.tag(loggerTag.value)
-                        .d("Send withheld $code req: ${request.shortDbgString()}")
-            }
-
-            cryptoStore.saveWithheldAuditTrail(
-                    roomId = request.roomId,
-                    sessionId = request.sessionId,
-                    senderKey = request.senderKey,
-                    algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
-                    code = code,
-                    userId = request.requestingUserId,
-                    deviceId = request.requestingDeviceId
-            )
-        } catch (failure: Throwable) {
-            // Ignore it's not that important?
-            // do we want to fallback to a worker?
-            Timber.tag(loggerTag.value)
-                    .w("Failed to send withheld $code req: ${request.shortDbgString()} reason:${failure.localizedMessage}")
-        }
-    }
-
-    suspend fun manuallyAcceptRoomKeyRequest(request: IncomingRoomKeyRequest) {
-        request.requestId ?: return
-        request.deviceId ?: return
-        request.userId ?: return
-        request.requestBody?.roomId ?: return
-        request.requestBody.senderKey ?: return
-        request.requestBody.sessionId ?: return
-        val validReq = ValidMegolmRequestBody(
-                requestId = request.requestId,
-                requestingDeviceId = request.deviceId,
-                requestingUserId = request.userId,
-                roomId = request.requestBody.roomId,
-                senderKey = request.requestBody.senderKey,
-                sessionId = request.requestBody.sessionId,
-                action = MegolmRequestAction.Request
-        )
-        val requestingDevice =
-                cryptoStore.getUserDevice(request.userId, request.deviceId)
-                        ?: return Unit.also {
-                            Timber.tag(loggerTag.value).d("Ignoring key request: ${validReq.shortDbgString()}")
-                        }
-
-        shareMegolmKey(validReq, requestingDevice, null)
-    }
-
-    private suspend fun shareMegolmKey(validRequest: ValidMegolmRequestBody,
-                                       requestingDevice: CryptoDeviceInfo,
-                                       chainIndex: Long?): Boolean {
-        Timber.tag(loggerTag.value)
-                .d("try to re-share Megolm Key at index $chainIndex for ${validRequest.shortDbgString()}")
-
-        val devicesByUser = mapOf(validRequest.requestingUserId to listOf(requestingDevice))
-        val usersDeviceMap = try {
-            ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value)
-                    .w("Failed to establish olm session")
-            sendWithheldForRequest(validRequest, WithHeldCode.NO_OLM)
-            return false
-        }
-
-        val olmSessionResult = usersDeviceMap.getObject(requestingDevice.userId, requestingDevice.deviceId)
-        if (olmSessionResult?.sessionId == null) {
-            Timber.tag(loggerTag.value)
-                    .w("reshareKey: no session with this device, probably because there were no one-time keys")
-            sendWithheldForRequest(validRequest, WithHeldCode.NO_OLM)
-            return false
-        }
-        val sessionHolder = try {
-            olmDevice.getInboundGroupSession(validRequest.sessionId, validRequest.senderKey, validRequest.roomId)
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value)
-                    .e(failure, "shareKeysWithDevice: failed to get session ${validRequest.requestingUserId}")
-            // It's unavailable
-            sendWithheldForRequest(validRequest, WithHeldCode.UNAVAILABLE)
-            return false
-        }
-
-        val export = sessionHolder.mutex.withLock {
-            sessionHolder.wrapper.exportKeys(chainIndex)
-        } ?: return false.also {
-            Timber.tag(loggerTag.value)
-                    .e("shareKeysWithDevice: failed to export group session ${validRequest.sessionId}")
-        }
-
-        val payloadJson = mapOf(
-                "type" to EventType.FORWARDED_ROOM_KEY,
-                "content" to export
-        )
-
-        val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(requestingDevice))
-        val sendToDeviceMap = MXUsersDevicesMap<Any>()
-        sendToDeviceMap.setObject(requestingDevice.userId, requestingDevice.deviceId, encodedPayload)
-        Timber.tag(loggerTag.value).d("reshareKey() : try sending session ${validRequest.sessionId} to ${requestingDevice.shortDebugString()}")
-        val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-        return try {
-            sendToDeviceTask.execute(sendToDeviceParams)
-            Timber.tag(loggerTag.value)
-                    .i("successfully re-shared session ${validRequest.sessionId} to ${requestingDevice.shortDebugString()}")
-            cryptoStore.saveForwardKeyAuditTrail(
-                    validRequest.roomId,
-                    validRequest.sessionId,
-                    validRequest.senderKey,
-                    MXCRYPTO_ALGORITHM_MEGOLM,
-                    requestingDevice.userId,
-                    requestingDevice.deviceId,
-                    chainIndex
-            )
-            true
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value)
-                    .e(failure, "fail to re-share session ${validRequest.sessionId} to ${requestingDevice.shortDebugString()}")
-            false
-        }
-    }
-
-    fun addRoomKeysRequestListener(listener: GossipingRequestListener) {
-        synchronized(gossipingRequestListeners) {
-            gossipingRequestListeners.add(listener)
-        }
-    }
-
-    fun removeRoomKeysRequestListener(listener: GossipingRequestListener) {
-        synchronized(gossipingRequestListeners) {
-            gossipingRequestListeners.remove(listener)
-        }
-    }
-
-    fun close() {
-        try {
-            outgoingRequestScope.cancel("User Terminate")
-            incomingRequestBuffer.clear()
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value).w("Failed to shutDown request manager")
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
deleted file mode 100755
index 82a8199bee..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt
+++ /dev/null
@@ -1,922 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import androidx.annotation.VisibleForTesting
-import kotlinx.coroutines.sync.Mutex
-import kotlinx.coroutines.sync.withLock
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
-import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE
-import org.matrix.android.sdk.api.util.JsonDict
-import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXOutboundSessionInfo
-import org.matrix.android.sdk.internal.crypto.algorithms.megolm.SharedWithHelper
-import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2
-import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.di.MoshiProvider
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.util.JsonCanonicalizer
-import org.matrix.android.sdk.internal.util.convertFromUTF8
-import org.matrix.android.sdk.internal.util.convertToUTF8
-import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.olm.OlmAccount
-import org.matrix.olm.OlmException
-import org.matrix.olm.OlmMessage
-import org.matrix.olm.OlmOutboundGroupSession
-import org.matrix.olm.OlmSession
-import org.matrix.olm.OlmUtility
-import timber.log.Timber
-import javax.inject.Inject
-
-private val loggerTag = LoggerTag("MXOlmDevice", LoggerTag.CRYPTO)
-
-// The libolm wrapper.
-@Deprecated("rust")
-@SessionScope
-internal class MXOlmDevice @Inject constructor(
-        /**
-         * The store where crypto data is saved.
-         */
-        private val store: IMXCryptoStore,
-        private val olmSessionStore: OlmSessionStore,
-        private val inboundGroupSessionStore: InboundGroupSessionStore,
-        private val clock: Clock,
-) {
-
-    val mutex = Mutex()
-
-    /**
-     * @return the Curve25519 key for the account.
-     */
-    var deviceCurve25519Key: String? = null
-        private set
-
-    /**
-     * @return the Ed25519 key for the account.
-     */
-    var deviceEd25519Key: String? = null
-        private set
-
-    // The OLM lib utility instance.
-    private var olmUtility: OlmUtility? = null
-
-    private data class GroupSessionCacheItem(
-            val groupId: String,
-            val groupSession: OlmOutboundGroupSession
-    )
-
-    // The outbound group session.
-    // Caches active outbound session to avoid to sync with DB before read
-    // The key is the session id, the value the <roomID,outbound group session>.
-    private val outboundGroupSessionCache: MutableMap<String, GroupSessionCacheItem> = HashMap()
-
-    // Store a set of decrypted message indexes for each group session.
-    // This partially mitigates a replay attack where a MITM resends a group
-    // message into the room.
-    //
-    // The Matrix SDK exposes events through MXEventTimelines. A developer can open several
-    // timelines from a same room so that a message can be decrypted several times but from
-    // a different timeline.
-    // So, store these message indexes per timeline id.
-    //
-    // The first level keys are timeline ids.
-    // The second level keys are strings of form "<senderKey>|<session_id>|<message_index>"
-    private val inboundGroupSessionMessageIndexes: MutableMap<String, MutableSet<String>> = HashMap()
-
-    init {
-        // Retrieve the account from the store
-        try {
-            store.getOrCreateOlmAccount()
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "MXOlmDevice : cannot initialize olmAccount")
-        }
-
-        try {
-            olmUtility = OlmUtility()
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## MXOlmDevice : OlmUtility failed with error")
-            olmUtility = null
-        }
-
-        try {
-            deviceCurve25519Key = store.doWithOlmAccount { it.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY] }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_IDENTITY_KEY} with error")
-        }
-
-        try {
-            deviceEd25519Key = store.doWithOlmAccount { it.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY] }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_FINGER_PRINT_KEY} with error")
-        }
-    }
-
-    /**
-     * @return The current (unused, unpublished) one-time keys for this account.
-     */
-    fun getOneTimeKeys(): Map<String, Map<String, String>>? {
-        try {
-            return store.doWithOlmAccount { it.oneTimeKeys() }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## getOneTimeKeys() : failed")
-        }
-
-        return null
-    }
-
-    /**
-     * @return The maximum number of one-time keys the olm account can store.
-     */
-    fun getMaxNumberOfOneTimeKeys(): Long {
-        return store.doWithOlmAccount { it.maxOneTimeKeys() }
-    }
-
-    /**
-     * Returns an unpublished fallback key
-     * A call to markKeysAsPublished will mark it as published and this
-     * call will return null (until a call to generateFallbackKey is made)
-     */
-    fun getFallbackKey(): MutableMap<String, MutableMap<String, String>>? {
-        try {
-            return store.doWithOlmAccount { it.fallbackKey() }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e("## getFallbackKey() : failed")
-        }
-        return null
-    }
-
-    /**
-     * Generates a new fallback key if there is not already
-     * an unpublished one.
-     * @return true if a new key was generated
-     */
-    fun generateFallbackKeyIfNeeded(): Boolean {
-        try {
-            if (!hasUnpublishedFallbackKey()) {
-                store.doWithOlmAccount {
-                    it.generateFallbackKey()
-                    store.saveOlmAccount()
-                }
-                return true
-            }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e("## generateFallbackKey() : failed")
-        }
-        return false
-    }
-
-    internal fun hasUnpublishedFallbackKey(): Boolean {
-        return getFallbackKey()?.get(OlmAccount.JSON_KEY_ONE_TIME_KEY).orEmpty().isNotEmpty()
-    }
-
-    fun forgetFallbackKey() {
-        try {
-            store.doWithOlmAccount {
-                it.forgetFallbackKey()
-                store.saveOlmAccount()
-            }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e("## forgetFallbackKey() : failed")
-        }
-    }
-
-    /**
-     * Release the instance
-     */
-    fun release() {
-        olmUtility?.releaseUtility()
-        outboundGroupSessionCache.values.forEach {
-            it.groupSession.releaseSession()
-        }
-        outboundGroupSessionCache.clear()
-        inboundGroupSessionStore.clear()
-        olmSessionStore.clear()
-    }
-
-    /**
-     * Signs a message with the ed25519 key for this account.
-     *
-     * @param message the message to be signed.
-     * @return the base64-encoded signature.
-     */
-    fun signMessage(message: String): String? {
-        try {
-            return store.doWithOlmAccount { it.signMessage(message) }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## signMessage() : failed")
-        }
-
-        return null
-    }
-
-    /**
-     * Marks all of the one-time keys as published.
-     */
-    fun markKeysAsPublished() {
-        try {
-            store.doWithOlmAccount {
-                it.markOneTimeKeysAsPublished()
-                store.saveOlmAccount()
-            }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## markKeysAsPublished() : failed")
-        }
-    }
-
-    /**
-     * Generate some new one-time keys
-     *
-     * @param numKeys number of keys to generate
-     */
-    fun generateOneTimeKeys(numKeys: Int) {
-        try {
-            store.doWithOlmAccount {
-                it.generateOneTimeKeys(numKeys)
-                store.saveOlmAccount()
-            }
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## generateOneTimeKeys() : failed")
-        }
-    }
-
-    /**
-     * Generate a new outbound session.
-     * The new session will be stored in the MXStore.
-     *
-     * @param theirIdentityKey the remote user's Curve25519 identity key
-     * @param theirOneTimeKey  the remote user's one-time Curve25519 key
-     * @return the session id for the outbound session.
-     */
-    fun createOutboundSession(theirIdentityKey: String, theirOneTimeKey: String): String? {
-        Timber.tag(loggerTag.value).d("## createOutboundSession() ; theirIdentityKey $theirIdentityKey theirOneTimeKey $theirOneTimeKey")
-        var olmSession: OlmSession? = null
-
-        try {
-            olmSession = OlmSession()
-            store.doWithOlmAccount { olmAccount ->
-                olmSession.initOutboundSession(olmAccount, theirIdentityKey, theirOneTimeKey)
-            }
-
-            val olmSessionWrapper = OlmSessionWrapper(olmSession, 0)
-
-            // Pretend we've received a message at this point, otherwise
-            // if we try to send a message to the device, it won't use
-            // this session
-            olmSessionWrapper.onMessageReceived(clock.epochMillis())
-
-            olmSessionStore.storeSession(olmSessionWrapper, theirIdentityKey)
-
-            val sessionIdentifier = olmSession.sessionIdentifier()
-
-            Timber.tag(loggerTag.value).v("## createOutboundSession() ;  olmSession.sessionIdentifier: $sessionIdentifier")
-            return sessionIdentifier
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## createOutboundSession() failed")
-
-            olmSession?.releaseSession()
-        }
-
-        return null
-    }
-
-    /**
-     * Generate a new inbound session, given an incoming message.
-     *
-     * @param theirDeviceIdentityKey the remote user's Curve25519 identity key.
-     * @param messageType            the message_type field from the received message (must be 0).
-     * @param ciphertext             base64-encoded body from the received message.
-     * @return {{payload: string, session_id: string}} decrypted payload, and session id of new session.
-     */
-    fun createInboundSession(theirDeviceIdentityKey: String, messageType: Int, ciphertext: String): Map<String, String>? {
-        Timber.tag(loggerTag.value).d("## createInboundSession() : theirIdentityKey: $theirDeviceIdentityKey")
-
-        var olmSession: OlmSession? = null
-
-        try {
-            try {
-                olmSession = OlmSession()
-                store.doWithOlmAccount { olmAccount ->
-                    olmSession.initInboundSessionFrom(olmAccount, theirDeviceIdentityKey, ciphertext)
-                }
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## createInboundSession() : the session creation failed")
-                return null
-            }
-
-            Timber.tag(loggerTag.value).v("## createInboundSession() : sessionId: ${olmSession.sessionIdentifier()}")
-
-            try {
-                store.doWithOlmAccount { olmAccount ->
-                    olmAccount.removeOneTimeKeys(olmSession)
-                    store.saveOlmAccount()
-                }
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## createInboundSession() : removeOneTimeKeys failed")
-            }
-
-            val olmMessage = OlmMessage()
-            olmMessage.mCipherText = ciphertext
-            olmMessage.mType = messageType.toLong()
-
-            var payloadString: String? = null
-
-            try {
-                payloadString = olmSession.decryptMessage(olmMessage)
-
-                val olmSessionWrapper = OlmSessionWrapper(olmSession, 0)
-                // This counts as a received message: set last received message time to now
-                olmSessionWrapper.onMessageReceived(clock.epochMillis())
-
-                olmSessionStore.storeSession(olmSessionWrapper, theirDeviceIdentityKey)
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## createInboundSession() : decryptMessage failed")
-            }
-
-            val res = HashMap<String, String>()
-
-            if (!payloadString.isNullOrEmpty()) {
-                res["payload"] = payloadString
-            }
-
-            val sessionIdentifier = olmSession.sessionIdentifier()
-
-            if (!sessionIdentifier.isNullOrEmpty()) {
-                res["session_id"] = sessionIdentifier
-            }
-
-            return res
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "## createInboundSession() : OlmSession creation failed")
-
-            olmSession?.releaseSession()
-        }
-
-        return null
-    }
-
-    /**
-     * Get a list of known session IDs for the given device.
-     *
-     * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @return a list of known session ids for the device.
-     */
-    fun getSessionIds(theirDeviceIdentityKey: String): List<String> {
-        return olmSessionStore.getDeviceSessionIds(theirDeviceIdentityKey)
-    }
-
-    /**
-     * Get the right olm session id for encrypting messages to the given identity key.
-     *
-     * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @return the session id, or null if no established session.
-     */
-    fun getSessionId(theirDeviceIdentityKey: String): String? {
-        return olmSessionStore.getLastUsedSessionId(theirDeviceIdentityKey)
-    }
-
-    /**
-     * Encrypt an outgoing message using an existing session.
-     *
-     * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @param sessionId              the id of the active session
-     * @param payloadString          the payload to be encrypted and sent
-     * @return the cipher text
-     */
-    suspend fun encryptMessage(theirDeviceIdentityKey: String, sessionId: String, payloadString: String): Map<String, Any>? {
-        val olmSessionWrapper = getSessionForDevice(theirDeviceIdentityKey, sessionId)
-
-        if (olmSessionWrapper != null) {
-            try {
-                Timber.tag(loggerTag.value).v("## encryptMessage() : olmSession.sessionIdentifier: $sessionId")
-
-                val olmMessage = olmSessionWrapper.mutex.withLock {
-                    olmSessionWrapper.olmSession.encryptMessage(payloadString)
-                }
-                return mapOf(
-                        "body" to olmMessage.mCipherText,
-                        "type" to olmMessage.mType,
-                ).also {
-                    olmSessionStore.storeSession(olmSessionWrapper, theirDeviceIdentityKey)
-                }
-            } catch (e: Throwable) {
-                Timber.tag(loggerTag.value).e(e, "## encryptMessage() : failed to encrypt olm with device|session:$theirDeviceIdentityKey|$sessionId")
-                return null
-            }
-        } else {
-            Timber.tag(loggerTag.value).e("## encryptMessage() : Failed to encrypt unknown session $sessionId")
-            return null
-        }
-    }
-
-    /**
-     * Decrypt an incoming message using an existing session.
-     *
-     * @param ciphertext             the base64-encoded body from the received message.
-     * @param messageType            message_type field from the received message.
-     * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @param sessionId              the id of the active session.
-     * @return the decrypted payload.
-     */
-    @kotlin.jvm.Throws
-    suspend fun decryptMessage(ciphertext: String, messageType: Int, sessionId: String, theirDeviceIdentityKey: String): String? {
-        var payloadString: String? = null
-
-        val olmSessionWrapper = getSessionForDevice(theirDeviceIdentityKey, sessionId)
-
-        if (null != olmSessionWrapper) {
-            val olmMessage = OlmMessage()
-            olmMessage.mCipherText = ciphertext
-            olmMessage.mType = messageType.toLong()
-
-            payloadString =
-                    olmSessionWrapper.mutex.withLock {
-                        olmSessionWrapper.olmSession.decryptMessage(olmMessage).also {
-                            olmSessionWrapper.onMessageReceived(clock.epochMillis())
-                        }
-                    }
-            olmSessionStore.storeSession(olmSessionWrapper, theirDeviceIdentityKey)
-        }
-
-        return payloadString
-    }
-
-    /**
-     * Determine if an incoming messages is a prekey message matching an existing session.
-     *
-     * @param theirDeviceIdentityKey the Curve25519 identity key for the remote device.
-     * @param sessionId              the id of the active session.
-     * @param messageType            message_type field from the received message.
-     * @param ciphertext             the base64-encoded body from the received message.
-     * @return YES if the received message is a prekey message which matchesthe given session.
-     */
-    fun matchesSession(theirDeviceIdentityKey: String, sessionId: String, messageType: Int, ciphertext: String): Boolean {
-        if (messageType != 0) {
-            return false
-        }
-
-        val olmSessionWrapper = getSessionForDevice(theirDeviceIdentityKey, sessionId)
-        return null != olmSessionWrapper && olmSessionWrapper.olmSession.matchesInboundSession(ciphertext)
-    }
-
-    // Outbound group session
-
-    /**
-     * Generate a new outbound group session.
-     *
-     * @return the session id for the outbound session.
-     */
-    fun createOutboundGroupSessionForRoom(roomId: String): String? {
-        var session: OlmOutboundGroupSession? = null
-        try {
-            session = OlmOutboundGroupSession()
-            outboundGroupSessionCache[session.sessionIdentifier()] = GroupSessionCacheItem(roomId, session)
-            store.storeCurrentOutboundGroupSessionForRoom(roomId, session)
-            return session.sessionIdentifier()
-        } catch (e: Exception) {
-            Timber.tag(loggerTag.value).e(e, "createOutboundGroupSession")
-
-            session?.releaseSession()
-        }
-
-        return null
-    }
-
-    fun storeOutboundGroupSessionForRoom(roomId: String, sessionId: String) {
-        outboundGroupSessionCache[sessionId]?.let {
-            store.storeCurrentOutboundGroupSessionForRoom(roomId, it.groupSession)
-        }
-    }
-
-    fun restoreOutboundGroupSessionForRoom(roomId: String): MXOutboundSessionInfo? {
-        val restoredOutboundGroupSession = store.getCurrentOutboundGroupSessionForRoom(roomId)
-        if (restoredOutboundGroupSession != null) {
-            val sessionId = restoredOutboundGroupSession.outboundGroupSession.sessionIdentifier()
-            // cache it
-            outboundGroupSessionCache[sessionId] = GroupSessionCacheItem(roomId, restoredOutboundGroupSession.outboundGroupSession)
-
-            return MXOutboundSessionInfo(
-                    sessionId = sessionId,
-                    sharedWithHelper = SharedWithHelper(roomId, sessionId, store),
-                    clock,
-                    restoredOutboundGroupSession.creationTime
-            )
-        }
-        return null
-    }
-
-    fun discardOutboundGroupSessionForRoom(roomId: String) {
-        val toDiscard = outboundGroupSessionCache.filter {
-            it.value.groupId == roomId
-        }
-        toDiscard.forEach { (sessionId, cacheItem) ->
-            cacheItem.groupSession.releaseSession()
-            outboundGroupSessionCache.remove(sessionId)
-        }
-        store.storeCurrentOutboundGroupSessionForRoom(roomId, null)
-    }
-
-    /**
-     * Get the current session key of  an outbound group session.
-     *
-     * @param sessionId the id of the outbound group session.
-     * @return the base64-encoded secret key.
-     */
-    fun getSessionKey(sessionId: String): String? {
-        if (sessionId.isNotEmpty()) {
-            try {
-                return outboundGroupSessionCache[sessionId]!!.groupSession.sessionKey()
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## getSessionKey() : failed")
-            }
-        }
-        return null
-    }
-
-    /**
-     * Get the current message index of an outbound group session.
-     *
-     * @param sessionId the id of the outbound group session.
-     * @return the current chain index.
-     */
-    fun getMessageIndex(sessionId: String): Int {
-        return if (sessionId.isNotEmpty()) {
-            outboundGroupSessionCache[sessionId]!!.groupSession.messageIndex()
-        } else 0
-    }
-
-    /**
-     * Encrypt an outgoing message with an outbound group session.
-     *
-     * @param sessionId     the id of the outbound group session.
-     * @param payloadString the payload to be encrypted and sent.
-     * @return ciphertext
-     */
-    fun encryptGroupMessage(sessionId: String, payloadString: String): String? {
-        if (sessionId.isNotEmpty() && payloadString.isNotEmpty()) {
-            try {
-                return outboundGroupSessionCache[sessionId]!!.groupSession.encryptMessage(payloadString)
-            } catch (e: Throwable) {
-                Timber.tag(loggerTag.value).e(e, "## encryptGroupMessage() : failed")
-            }
-        }
-        return null
-    }
-
-    //  Inbound group session
-
-    sealed interface AddSessionResult {
-        data class Imported(val ratchetIndex: Int) : AddSessionResult
-        abstract class Failure : AddSessionResult
-        object NotImported : Failure()
-        data class NotImportedHigherIndex(val newIndex: Int) : Failure()
-    }
-
-    /**
-     * Add an inbound group session to the session store.
-     *
-     * @param sessionId                    the session identifier.
-     * @param sessionKey                   base64-encoded secret key.
-     * @param roomId                       the id of the room in which this session will be used.
-     * @param senderKey                    the base64-encoded curve25519 key of the sender.
-     * @param forwardingCurve25519KeyChain Devices involved in forwarding this session to us.
-     * @param keysClaimed                  Other keys the sender claims.
-     * @param exportFormat                 true if the megolm keys are in export format
-     * @return true if the operation succeeds.
-     */
-    fun addInboundGroupSession(sessionId: String,
-                               sessionKey: String,
-                               roomId: String,
-                               senderKey: String,
-                               forwardingCurve25519KeyChain: List<String>,
-                               keysClaimed: Map<String, String>,
-                               exportFormat: Boolean): AddSessionResult {
-        val candidateSession = OlmInboundGroupSessionWrapper2(sessionKey, exportFormat)
-        val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) }
-        val existingSession = existingSessionHolder?.wrapper
-        // If we have an existing one we should check if the new one is not better
-        if (existingSession != null) {
-            Timber.tag(loggerTag.value).d("## addInboundGroupSession() check if known session is better than candidate session")
-            try {
-                val existingFirstKnown = existingSession.firstKnownIndex ?: return AddSessionResult.NotImported.also {
-                    // This is quite unexpected, could throw if native was released?
-                    Timber.tag(loggerTag.value).e("## addInboundGroupSession() null firstKnownIndex on existing session")
-                    candidateSession.olmInboundGroupSession?.releaseSession()
-                    // Probably should discard it?
-                }
-                val newKnownFirstIndex = candidateSession.firstKnownIndex
-                // If our existing session is better we keep it
-                if (newKnownFirstIndex != null && existingFirstKnown <= newKnownFirstIndex) {
-                    Timber.tag(loggerTag.value).d("## addInboundGroupSession() : ignore session our is better $senderKey/$sessionId")
-                    candidateSession.olmInboundGroupSession?.releaseSession()
-                    return AddSessionResult.NotImportedHigherIndex(newKnownFirstIndex.toInt())
-                }
-            } catch (failure: Throwable) {
-                Timber.tag(loggerTag.value).e("## addInboundGroupSession() Failed to add inbound: ${failure.localizedMessage}")
-                candidateSession.olmInboundGroupSession?.releaseSession()
-                return AddSessionResult.NotImported
-            }
-        }
-
-        Timber.tag(loggerTag.value).d("## addInboundGroupSession() : Candidate session should be added $senderKey/$sessionId")
-
-        // sanity check on the new session
-        val candidateOlmInboundSession = candidateSession.olmInboundGroupSession
-        if (null == candidateOlmInboundSession) {
-            Timber.tag(loggerTag.value).e("## addInboundGroupSession : invalid session <null>")
-            return AddSessionResult.NotImported
-        }
-
-        try {
-            if (candidateOlmInboundSession.sessionIdentifier() != sessionId) {
-                Timber.tag(loggerTag.value).e("## addInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey")
-                candidateOlmInboundSession.releaseSession()
-                return AddSessionResult.NotImported
-            }
-        } catch (e: Throwable) {
-            candidateOlmInboundSession.releaseSession()
-            Timber.tag(loggerTag.value).e(e, "## addInboundGroupSession : sessionIdentifier() failed")
-            return AddSessionResult.NotImported
-        }
-
-        candidateSession.senderKey = senderKey
-        candidateSession.roomId = roomId
-        candidateSession.keysClaimed = keysClaimed
-        candidateSession.forwardingCurve25519KeyChain = forwardingCurve25519KeyChain
-
-        if (existingSession != null) {
-            inboundGroupSessionStore.replaceGroupSession(existingSessionHolder, InboundGroupSessionHolder(candidateSession), sessionId, senderKey)
-        } else {
-            inboundGroupSessionStore.storeInBoundGroupSession(InboundGroupSessionHolder(candidateSession), sessionId, senderKey)
-        }
-
-        return AddSessionResult.Imported(candidateSession.firstKnownIndex?.toInt() ?: 0)
-    }
-
-    /**
-     * Import an inbound group sessions to the session store.
-     *
-     * @param megolmSessionsData the megolm sessions data
-     * @return the successfully imported sessions.
-     */
-    fun importInboundGroupSessions(megolmSessionsData: List<MegolmSessionData>): List<OlmInboundGroupSessionWrapper2> {
-        val sessions = ArrayList<OlmInboundGroupSessionWrapper2>(megolmSessionsData.size)
-
-        for (megolmSessionData in megolmSessionsData) {
-            val sessionId = megolmSessionData.sessionId ?: continue
-            val senderKey = megolmSessionData.senderKey ?: continue
-            val roomId = megolmSessionData.roomId
-
-            var candidateSessionToImport: OlmInboundGroupSessionWrapper2? = null
-
-            try {
-                candidateSessionToImport = OlmInboundGroupSessionWrapper2(megolmSessionData)
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## importInboundGroupSession() : Update for megolm session $senderKey/$sessionId")
-            }
-
-            // sanity check
-            if (candidateSessionToImport?.olmInboundGroupSession == null) {
-                Timber.tag(loggerTag.value).e("## importInboundGroupSession : invalid session")
-                continue
-            }
-
-            val candidateOlmInboundGroupSession = candidateSessionToImport.olmInboundGroupSession
-            try {
-                if (candidateOlmInboundGroupSession?.sessionIdentifier() != sessionId) {
-                    Timber.tag(loggerTag.value).e("## importInboundGroupSession : ERROR: Mismatched group session ID from senderKey: $senderKey")
-                    candidateOlmInboundGroupSession?.releaseSession()
-                    continue
-                }
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e(e, "## importInboundGroupSession : sessionIdentifier() failed")
-                candidateOlmInboundGroupSession?.releaseSession()
-                continue
-            }
-
-            val existingSessionHolder = tryOrNull { getInboundGroupSession(sessionId, senderKey, roomId) }
-            val existingSession = existingSessionHolder?.wrapper
-
-            if (existingSession == null) {
-                // Session does not already exist, add it
-                Timber.tag(loggerTag.value).d("## importInboundGroupSession() : importing new megolm session $senderKey/$sessionId")
-                sessions.add(candidateSessionToImport)
-            } else {
-                Timber.tag(loggerTag.value).e("## importInboundGroupSession() : Update for megolm session $senderKey/$sessionId")
-                val existingFirstKnown = tryOrNull { existingSession.firstKnownIndex }
-                val candidateFirstKnownIndex = tryOrNull { candidateSessionToImport.firstKnownIndex }
-
-                if (existingFirstKnown == null || candidateFirstKnownIndex == null) {
-                    // should not happen?
-                    candidateSessionToImport.olmInboundGroupSession?.releaseSession()
-                    Timber.tag(loggerTag.value)
-                            .w("## importInboundGroupSession() : Can't check session null index $existingFirstKnown/$candidateFirstKnownIndex")
-                } else {
-                    if (existingFirstKnown <= candidateSessionToImport.firstKnownIndex!!) {
-                        // Ignore this, keep existing
-                        candidateOlmInboundGroupSession.releaseSession()
-                    } else {
-                        // update cache with better session
-                        inboundGroupSessionStore.replaceGroupSession(
-                                existingSessionHolder,
-                                InboundGroupSessionHolder(candidateSessionToImport),
-                                sessionId,
-                                senderKey
-                        )
-                        sessions.add(candidateSessionToImport)
-                    }
-                }
-            }
-        }
-
-        store.storeInboundGroupSessions(sessions)
-
-        return sessions
-    }
-
-    /**
-     * Decrypt a received message with an inbound group session.
-     *
-     * @param body      the base64-encoded body of the encrypted message.
-     * @param roomId    the room in which the message was received.
-     * @param timeline  the id of the timeline where the event is decrypted. It is used to prevent replay attack.
-     * @param sessionId the session identifier.
-     * @param senderKey the base64-encoded curve25519 key of the sender.
-     * @return the decrypting result. Nil if the sessionId is unknown.
-     */
-    @Throws(MXCryptoError::class)
-    suspend fun decryptGroupMessage(body: String,
-                                    roomId: String,
-                                    timeline: String?,
-                                    sessionId: String,
-                                    senderKey: String): OlmDecryptionResult {
-        val sessionHolder = getInboundGroupSession(sessionId, senderKey, roomId)
-        val wrapper = sessionHolder.wrapper
-        val inboundGroupSession = wrapper.olmInboundGroupSession
-                ?: throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, "Session is null")
-        // Check that the room id matches the original one for the session. This stops
-        // the HS pretending a message was targeting a different room.
-        if (roomId == wrapper.roomId) {
-            val decryptResult = try {
-                sessionHolder.mutex.withLock {
-                    inboundGroupSession.decryptMessage(body)
-                }
-            } catch (e: OlmException) {
-                Timber.tag(loggerTag.value).e(e, "## decryptGroupMessage () : decryptMessage failed")
-                throw MXCryptoError.OlmError(e)
-            }
-
-            if (timeline?.isNotBlank() == true) {
-                val timelineSet = inboundGroupSessionMessageIndexes.getOrPut(timeline) { mutableSetOf() }
-
-                val messageIndexKey = senderKey + "|" + sessionId + "|" + decryptResult.mIndex
-
-                if (timelineSet.contains(messageIndexKey)) {
-                    val reason = String.format(MXCryptoError.DUPLICATE_MESSAGE_INDEX_REASON, decryptResult.mIndex)
-                    Timber.tag(loggerTag.value).e("## decryptGroupMessage() timelineId=$timeline: $reason")
-                    throw MXCryptoError.Base(MXCryptoError.ErrorType.DUPLICATED_MESSAGE_INDEX, reason)
-                }
-
-                timelineSet.add(messageIndexKey)
-            }
-
-            inboundGroupSessionStore.storeInBoundGroupSession(sessionHolder, sessionId, senderKey)
-            val payload = try {
-                val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
-                val payloadString = convertFromUTF8(decryptResult.mDecryptedMessage)
-                adapter.fromJson(payloadString)
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).e("## decryptGroupMessage() : fails to parse the payload")
-                throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON)
-            }
-
-            return OlmDecryptionResult(
-                    payload,
-                    wrapper.keysClaimed,
-                    senderKey,
-                    wrapper.forwardingCurve25519KeyChain
-            )
-        } else {
-            val reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, wrapper.roomId)
-            Timber.tag(loggerTag.value).e("## decryptGroupMessage() : $reason")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.INBOUND_SESSION_MISMATCH_ROOM_ID, reason)
-        }
-    }
-
-    /**
-     * Reset replay attack data for the given timeline.
-     *
-     * @param timeline the id of the timeline.
-     */
-    fun resetReplayAttackCheckInTimeline(timeline: String?) {
-        if (null != timeline) {
-            inboundGroupSessionMessageIndexes.remove(timeline)
-        }
-    }
-
-//  Utilities
-
-    /**
-     * Verify an ed25519 signature on a JSON object.
-     *
-     * @param key            the ed25519 key.
-     * @param jsonDictionary the JSON object which was signed.
-     * @param signature      the base64-encoded signature to be checked.
-     * @throws Exception the exception
-     */
-    @Throws(Exception::class)
-    fun verifySignature(key: String, jsonDictionary: Map<String, Any>, signature: String) {
-        // Check signature on the canonical version of the JSON
-        olmUtility!!.verifyEd25519Signature(signature, key, JsonCanonicalizer.getCanonicalJson(Map::class.java, jsonDictionary))
-    }
-
-    /**
-     * Calculate the SHA-256 hash of the input and encodes it as base64.
-     *
-     * @param message the message to hash.
-     * @return the base64-encoded hash value.
-     */
-    fun sha256(message: String): String {
-        return olmUtility!!.sha256(convertToUTF8(message))
-    }
-
-    /**
-     * Search an OlmSession
-     *
-     * @param theirDeviceIdentityKey the device key
-     * @param sessionId              the session Id
-     * @return the olm session
-     */
-    private fun getSessionForDevice(theirDeviceIdentityKey: String, sessionId: String): OlmSessionWrapper? {
-        // sanity check
-        return if (theirDeviceIdentityKey.isEmpty() || sessionId.isEmpty()) null else {
-            olmSessionStore.getDeviceSession(sessionId, theirDeviceIdentityKey)
-        }
-    }
-
-    /**
-     * Extract an InboundGroupSession from the session store and do some check.
-     * inboundGroupSessionWithIdError describes the failure reason.
-     *
-     * @param roomId    the room where the session is used.
-     * @param sessionId the session identifier.
-     * @param senderKey the base64-encoded curve25519 key of the sender.
-     * @return the inbound group session.
-     */
-    fun getInboundGroupSession(sessionId: String?, senderKey: String?, roomId: String?): InboundGroupSessionHolder {
-        if (sessionId.isNullOrBlank() || senderKey.isNullOrBlank()) {
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_SENDER_KEY, MXCryptoError.ERROR_MISSING_PROPERTY_REASON)
-        }
-
-        val holder = inboundGroupSessionStore.getInboundGroupSession(sessionId, senderKey)
-        val session = holder?.wrapper
-
-        if (session != null) {
-            // Check that the room id matches the original one for the session. This stops
-            // the HS pretending a message was targeting a different room.
-            if (roomId != session.roomId) {
-                val errorDescription = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, session.roomId)
-                Timber.tag(loggerTag.value).e("## getInboundGroupSession() : $errorDescription")
-                throw MXCryptoError.Base(MXCryptoError.ErrorType.INBOUND_SESSION_MISMATCH_ROOM_ID, errorDescription)
-            } else {
-                return holder
-            }
-        } else {
-            Timber.tag(loggerTag.value).w("## getInboundGroupSession() : UISI $sessionId")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID, MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_REASON)
-        }
-    }
-
-    /**
-     * Determine if we have the keys for a given megolm session.
-     *
-     * @param roomId    room in which the message was received
-     * @param senderKey base64-encoded curve25519 key of the sender
-     * @param sessionId session identifier
-     * @return true if the unbound session keys are known.
-     */
-    fun hasInboundSessionKeys(roomId: String, senderKey: String, sessionId: String): Boolean {
-        return runCatching { getInboundGroupSession(sessionId, senderKey, roomId) }.isSuccess
-    }
-
-    @VisibleForTesting
-    fun clearOlmSessionCache() {
-        olmSessionStore.clear()
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionImportManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionImportManager.kt
index a6b215ae6b..b73bb96a7d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionImportManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MegolmSessionImportManager.kt
@@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.session.crypto.NewSessionListener
 import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
 import org.matrix.android.sdk.internal.session.SessionScope
 import javax.inject.Inject
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt
deleted file mode 100644
index 9798d21576..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MyDeviceInfoHolder.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import org.matrix.android.sdk.api.auth.data.Credentials
-import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.session.SessionScope
-import javax.inject.Inject
-
-@SessionScope
-internal class MyDeviceInfoHolder @Inject constructor(
-        // The credentials,
-        credentials: Credentials,
-        // the crypto store
-        cryptoStore: IMXCryptoStore,
-        // Olm device
-        olmDevice: MXOlmDevice
-) {
-    // Our device keys
-    /**
-     * my device info
-     */
-    val myDevice: CryptoDeviceInfo
-
-    init {
-
-        val keys = HashMap<String, String>()
-
-// TODO it's a bit strange, why not load from DB?
-        if (!olmDevice.deviceEd25519Key.isNullOrEmpty()) {
-            keys["ed25519:" + credentials.deviceId] = olmDevice.deviceEd25519Key!!
-        }
-
-        if (!olmDevice.deviceCurve25519Key.isNullOrEmpty()) {
-            keys["curve25519:" + credentials.deviceId] = olmDevice.deviceCurve25519Key!!
-        }
-
-//        myDevice.keys = keys
-//
-//        myDevice.algorithms = MXCryptoAlgorithms.supportedAlgorithms()
-
-        // TODO hwo to really check cross signed status?
-        //
-        val crossSigned = cryptoStore.getMyCrossSigningInfo()?.masterKey()?.trustLevel?.locallyVerified ?: false
-//        myDevice.trustLevel = DeviceTrustLevel(crossSigned, true)
-
-        myDevice = CryptoDeviceInfo(
-                credentials.deviceId!!,
-                credentials.userId,
-                keys = keys,
-                algorithms = MXCryptoAlgorithms.supportedAlgorithms(),
-                trustLevel = DeviceTrustLevel(crossSigned, true)
-        )
-
-        // Add our own deviceinfo to the store
-        val endToEndDevicesForUser = cryptoStore.getUserDevices(credentials.userId)
-
-        val myDevices = endToEndDevicesForUser.orEmpty().toMutableMap()
-
-        myDevices[myDevice.deviceId] = myDevice
-
-        cryptoStore.storeUserDevices(credentials.userId, myDevices)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt
deleted file mode 100644
index 68dd17324b..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ObjectSigner.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import org.matrix.android.sdk.api.auth.data.Credentials
-import javax.inject.Inject
-
-internal class ObjectSigner @Inject constructor(private val credentials: Credentials,
-                                                private val olmDevice: MXOlmDevice) {
-
-    /**
-     * Sign Object
-     *
-     * Example:
-     * <pre>
-     *     {
-     *         "[MY_USER_ID]": {
-     *             "ed25519:[MY_DEVICE_ID]": "sign(str)"
-     *         }
-     *     }
-     * </pre>
-     *
-     * @param strToSign the String to sign and to include in the Map
-     * @return a Map (see example)
-     */
-    fun signObject(strToSign: String): Map<String, Map<String, String>> {
-        val result = HashMap<String, Map<String, String>>()
-
-        val content = HashMap<String, String>()
-
-        content["ed25519:" + credentials.deviceId] = olmDevice.signMessage(strToSign)
-                ?: "" // null reported by rageshake if happens during logout
-
-        result[credentials.userId] = content
-
-        return result
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt
deleted file mode 100644
index 8143e36892..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import android.content.Context
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.internal.crypto.model.MXKey
-import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
-import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.util.JsonCanonicalizer
-import org.matrix.android.sdk.internal.util.time.Clock
-import org.matrix.olm.OlmAccount
-import timber.log.Timber
-import javax.inject.Inject
-import kotlin.math.floor
-import kotlin.math.min
-
-// The spec recommend a 5mn delay, but due to federation
-// or server downtime we give it a bit more time (1 hour)
-private const val FALLBACK_KEY_FORGET_DELAY = 60 * 60_000L
-
-@SessionScope
-internal class OneTimeKeysUploader @Inject constructor(
-        private val olmDevice: MXOlmDevice,
-        private val objectSigner: ObjectSigner,
-        private val uploadKeysTask: UploadKeysTask,
-        private val clock: Clock,
-        context: Context
-) {
-    // tell if there is a OTK check in progress
-    private var oneTimeKeyCheckInProgress = false
-
-    // last OTK check timestamp
-    private var lastOneTimeKeyCheck: Long = 0
-    private var oneTimeKeyCount: Int? = null
-
-    // Simple storage to remember when was uploaded the last fallback key
-    private val storage = context.getSharedPreferences("OneTimeKeysUploader_${olmDevice.deviceEd25519Key.hashCode()}", Context.MODE_PRIVATE)
-
-    /**
-     * Stores the current one_time_key count which will be handled later (in a call of
-     * _onSyncCompleted). The count is e.g. coming from a /sync response.
-     *
-     * @param currentCount the new count
-     */
-    fun updateOneTimeKeyCount(currentCount: Int) {
-        oneTimeKeyCount = currentCount
-    }
-
-    fun needsNewFallback() {
-        if (olmDevice.generateFallbackKeyIfNeeded()) {
-            // As we generated a new one, it's already forgetting one
-            // so we can clear the last publish time
-            // (in case the network calls fails after to avoid calling forgetKey)
-            saveLastFallbackKeyPublishTime(0L)
-        }
-    }
-
-    /**
-     * Check if the OTK must be uploaded.
-     */
-    suspend fun maybeUploadOneTimeKeys() {
-        if (oneTimeKeyCheckInProgress) {
-            Timber.v("maybeUploadOneTimeKeys: already in progress")
-            return
-        }
-        if (clock.epochMillis() - lastOneTimeKeyCheck < ONE_TIME_KEY_UPLOAD_PERIOD) {
-            // we've done a key upload recently.
-            Timber.v("maybeUploadOneTimeKeys: executed too recently")
-            return
-        }
-
-        oneTimeKeyCheckInProgress = true
-
-        val oneTimeKeyCountFromSync = oneTimeKeyCount
-                ?: fetchOtkCount() // we don't have count from sync so get from server
-                ?: return Unit.also {
-                    oneTimeKeyCheckInProgress = false
-                    Timber.w("maybeUploadOneTimeKeys: Failed to get otk count from server")
-                }
-
-        Timber.d("maybeUploadOneTimeKeys: otk count $oneTimeKeyCountFromSync , unpublished fallback key ${olmDevice.hasUnpublishedFallbackKey()}")
-
-        lastOneTimeKeyCheck = clock.epochMillis()
-
-        // We then check how many keys we can store in the Account object.
-        val maxOneTimeKeys = olmDevice.getMaxNumberOfOneTimeKeys()
-
-        // Try to keep at most half that number on the server. This leaves the
-        // rest of the slots free to hold keys that have been claimed from the
-        // server but we haven't received a message for.
-        // If we run out of slots when generating new keys then olm will
-        // discard the oldest private keys first. This will eventually clean
-        // out stale private keys that won't receive a message.
-        val keyLimit = floor(maxOneTimeKeys / 2.0).toInt()
-
-        // We need to keep a pool of one time public keys on the server so that
-        // other devices can start conversations with us. But we can only store
-        // a finite number of private keys in the olm Account object.
-        // To complicate things further then can be a delay between a device
-        // claiming a public one time key from the server and it sending us a
-        // message. We need to keep the corresponding private key locally until
-        // we receive the message.
-        // But that message might never arrive leaving us stuck with duff
-        // private keys clogging up our local storage.
-        // So we need some kind of engineering compromise to balance all of
-        // these factors.
-        tryOrNull("Unable to upload OTK") {
-            val uploadedKeys = uploadOTK(oneTimeKeyCountFromSync, keyLimit)
-            Timber.v("## uploadKeys() : success, $uploadedKeys key(s) sent")
-        }
-        oneTimeKeyCheckInProgress = false
-
-        // Check if we need to forget a fallback key
-        val latestPublishedTime = getLastFallbackKeyPublishTime()
-        if (latestPublishedTime != 0L && clock.epochMillis() - latestPublishedTime > FALLBACK_KEY_FORGET_DELAY) {
-            // This should be called once you are reasonably certain that you will not receive any more messages
-            // that use the old fallback key
-            Timber.d("## forgetFallbackKey()")
-            olmDevice.forgetFallbackKey()
-        }
-    }
-
-    private suspend fun fetchOtkCount(): Int? {
-        return tryOrNull("Unable to get OTK count") {
-            val result = uploadKeysTask.execute(UploadKeysTask.Params(null, null, null))
-            result.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)
-        }
-    }
-
-    /**
-     * Upload some the OTKs.
-     *
-     * @param keyCount the key count
-     * @param keyLimit the limit
-     * @return the number of uploaded keys
-     */
-    private suspend fun uploadOTK(keyCount: Int, keyLimit: Int): Int {
-        if (keyLimit <= keyCount && !olmDevice.hasUnpublishedFallbackKey()) {
-            // If we don't need to generate any more keys then we are done.
-            return 0
-        }
-        var keysThisLoop = 0
-        if (keyLimit > keyCount) {
-            // Creating keys can be an expensive operation so we limit the
-            // number we generate in one go to avoid blocking the application
-            // for too long.
-            keysThisLoop = min(keyLimit - keyCount, ONE_TIME_KEY_GENERATION_MAX_NUMBER)
-            olmDevice.generateOneTimeKeys(keysThisLoop)
-        }
-
-        // We check before sending if there is an unpublished key in order to saveLastFallbackKeyPublishTime if needed
-        val hadUnpublishedFallbackKey = olmDevice.hasUnpublishedFallbackKey()
-        val response = uploadOneTimeKeys(olmDevice.getOneTimeKeys())
-        olmDevice.markKeysAsPublished()
-        if (hadUnpublishedFallbackKey) {
-            // It had an unpublished fallback key that was published just now
-            saveLastFallbackKeyPublishTime(clock.epochMillis())
-        }
-
-        if (response.hasOneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE)) {
-            // Maybe upload other keys
-            return keysThisLoop +
-                    uploadOTK(response.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE), keyLimit) +
-                    (if (hadUnpublishedFallbackKey) 1 else 0)
-        } else {
-            Timber.e("## uploadOTK() : response for uploading keys does not contain one_time_key_counts.signed_curve25519")
-            throw Exception("response for uploading keys does not contain one_time_key_counts.signed_curve25519")
-        }
-    }
-
-    private fun saveLastFallbackKeyPublishTime(timeMillis: Long) {
-        storage.edit().putLong("last_fb_key_publish", timeMillis).apply()
-    }
-
-    private fun getLastFallbackKeyPublishTime(): Long {
-        return storage.getLong("last_fb_key_publish", 0)
-    }
-
-    /**
-     * Upload curve25519 one time keys.
-     */
-    private suspend fun uploadOneTimeKeys(oneTimeKeys: Map<String, Map<String, String>>?): KeysUploadResponse {
-        val oneTimeJson = mutableMapOf<String, Any>()
-
-        val curve25519Map = oneTimeKeys?.get(OlmAccount.JSON_KEY_ONE_TIME_KEY).orEmpty()
-
-        curve25519Map.forEach { (key_id, value) ->
-            val k = mutableMapOf<String, Any>()
-            k["key"] = value
-
-            // the key is also signed
-            val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, k)
-
-            k["signatures"] = objectSigner.signObject(canonicalJson)
-
-            oneTimeJson["signed_curve25519:$key_id"] = k
-        }
-
-        val fallbackJson = mutableMapOf<String, Any>()
-        val fallbackCurve25519Map = olmDevice.getFallbackKey()?.get(OlmAccount.JSON_KEY_ONE_TIME_KEY).orEmpty()
-        fallbackCurve25519Map.forEach { (key_id, key) ->
-            val k = mutableMapOf<String, Any>()
-            k["key"] = key
-            k["fallback"] = true
-            val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, k)
-            k["signatures"] = objectSigner.signObject(canonicalJson)
-
-            fallbackJson["signed_curve25519:$key_id"] = k
-        }
-
-        // For now, we set the device id explicitly, as we may not be using the
-        // same one as used in login.
-        val uploadParams = UploadKeysTask.Params(
-                deviceKeys = null,
-                oneTimeKeys = oneTimeJson,
-                fallbackKeys = fallbackJson.takeIf { fallbackJson.isNotEmpty() }
-        )
-        return uploadKeysTask.executeRetry(uploadParams, 3)
-    }
-
-    companion object {
-        // max number of keys to upload at once
-        // Creating keys can be an expensive operation so we limit the
-        // number we generate in one go to avoid blocking the application
-        // for too long.
-        private const val ONE_TIME_KEY_GENERATION_MAX_NUMBER = 5
-
-        // frequency with which to check & upload one-time keys
-        private const val ONE_TIME_KEY_UPLOAD_PERIOD = (60_000).toLong() // one minute
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
deleted file mode 100755
index 09a9868428..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingKeyRequestManager.kt
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
-import org.matrix.android.sdk.api.crypto.MXCryptoConfig
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
-import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
-import org.matrix.android.sdk.api.session.crypto.model.GossipingToDeviceObject
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyRequestBody
-import org.matrix.android.sdk.api.session.crypto.model.RoomKeyShareRequest
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.api.util.fromBase64
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.di.SessionId
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.task.SemaphoreCoroutineSequencer
-import timber.log.Timber
-import java.util.Stack
-import java.util.concurrent.Executors
-import javax.inject.Inject
-import kotlin.system.measureTimeMillis
-
-private val loggerTag = LoggerTag("OutgoingKeyRequestManager", LoggerTag.CRYPTO)
-
-/**
- * This class is responsible for sending key requests to other devices when a message failed to decrypt.
- * It's lifecycle is based on the sync pulse:
- *    - You can post queries for session, or report when you got a session
- *    - At the end of the sync (onSyncComplete) it will then process all the posted request and send to devices
- * If a request failed it will be retried at the end of the next sync
- */
-@SessionScope
-internal class OutgoingKeyRequestManager @Inject constructor(
-        @SessionId private val sessionId: String,
-        @UserId private val myUserId: String,
-        private val cryptoStore: IMXCryptoStore,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoConfig: MXCryptoConfig,
-        private val inboundGroupSessionStore: InboundGroupSessionStore,
-        private val sendToDeviceTask: SendToDeviceTask,
-        private val deviceListManager: DeviceListManager,
-        private val perSessionBackupQueryRateLimiter: PerSessionBackupQueryRateLimiter) {
-
-    private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
-    private val outgoingRequestScope = CoroutineScope(SupervisorJob() + dispatcher)
-    private val sequencer = SemaphoreCoroutineSequencer()
-
-    // We only have one active key request per session, so we don't request if it's already requested
-    // But it could make sense to check more the backup, as it's evolving.
-    // We keep a stack as we consider that the key requested last is more likely to be on screen?
-    private val requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup = Stack<Pair<String, String>>()
-
-    fun requestKeyForEvent(event: Event, force: Boolean) {
-        val (targets, body) = getRoomKeyRequestTargetForEvent(event) ?: return
-        val index = ratchetIndexForMessage(event) ?: 0
-        postRoomKeyRequest(body, targets, index, force)
-    }
-
-    private fun getRoomKeyRequestTargetForEvent(event: Event): Pair<Map<String, List<String>>, RoomKeyRequestBody>? {
-        val sender = event.senderId ?: return null
-        val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return null.also {
-            Timber.tag(loggerTag.value).e("getRoomKeyRequestTargetForEvent Failed to re-request key, null content")
-        }
-        if (encryptedEventContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
-
-        val senderDevice = encryptedEventContent.deviceId
-        val recipients = if (cryptoConfig.limitRoomKeyRequestsToMyDevices) {
-            mapOf(
-                    myUserId to listOf("*")
-            )
-        } else {
-            if (event.senderId == myUserId) {
-                mapOf(
-                        myUserId to listOf("*")
-                )
-            } else {
-                // for the case where you share the key with a device that has a broken olm session
-                // The other user might Re-shares a megolm session key with devices if the key has already been
-                // sent to them.
-                mapOf(
-                        myUserId to listOf("*"),
-
-                        // We might not have deviceId in the future due to https://github.com/matrix-org/matrix-spec-proposals/pull/3700
-                        // so in this case query to all
-                        sender to listOf(senderDevice ?: "*")
-                )
-            }
-        }
-
-        val requestBody = RoomKeyRequestBody(
-                roomId = event.roomId,
-                algorithm = encryptedEventContent.algorithm,
-                senderKey = encryptedEventContent.senderKey,
-                sessionId = encryptedEventContent.sessionId
-        )
-        return recipients to requestBody
-    }
-
-    private fun ratchetIndexForMessage(event: Event): Int? {
-        val encryptedContent = event.content.toModel<EncryptedEventContent>() ?: return null
-        if (encryptedContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
-        return encryptedContent.ciphertext?.fromBase64()?.inputStream()?.reader()?.let {
-            tryOrNull {
-                val megolmVersion = it.read()
-                if (megolmVersion != 3) return@tryOrNull null
-                /** Int tag */
-                if (it.read() != 8) return@tryOrNull null
-                it.read()
-            }
-        }
-    }
-
-    fun postRoomKeyRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int, force: Boolean = false) {
-        outgoingRequestScope.launch {
-            sequencer.post {
-                internalQueueRequest(requestBody, recipients, fromIndex, force)
-            }
-        }
-    }
-
-    /**
-     * Typically called when we the session as been imported or received meanwhile
-     */
-    fun postCancelRequestForSessionIfNeeded(sessionId: String, roomId: String, senderKey: String, fromIndex: Int) {
-        outgoingRequestScope.launch {
-            sequencer.post {
-                internalQueueCancelRequest(sessionId, roomId, senderKey, fromIndex)
-            }
-        }
-    }
-
-    fun onSelfCrossSigningTrustChanged(newTrust: Boolean) {
-        if (newTrust) {
-            // we were previously not cross signed, but we are now
-            // so there is now more chances to get better replies for existing request
-            // Let's forget about sent request so that next time we try to decrypt we will resend requests
-            // We don't resend all because we don't want to generate a bulk of traffic
-            outgoingRequestScope.launch {
-                sequencer.post {
-                    cryptoStore.deleteOutgoingRoomKeyRequestInState(OutgoingRoomKeyRequestState.SENT)
-                }
-
-                sequencer.post {
-                    delay(1000)
-                    perSessionBackupQueryRateLimiter.refreshBackupInfoIfNeeded(true)
-                }
-            }
-        }
-    }
-
-    fun onRoomKeyForwarded(sessionId: String,
-                           algorithm: String,
-                           roomId: String,
-                           senderKey: String,
-                           fromDevice: String?,
-                           fromIndex: Int,
-                           event: Event) {
-        Timber.tag(loggerTag.value).d("Key forwarded for $sessionId from ${event.senderId}|$fromDevice at index $fromIndex")
-        outgoingRequestScope.launch {
-            sequencer.post {
-                cryptoStore.updateOutgoingRoomKeyReply(
-                        roomId = roomId,
-                        sessionId = sessionId,
-                        algorithm = algorithm,
-                        senderKey = senderKey,
-                        fromDevice = fromDevice,
-                        // strip out encrypted stuff as it's just a trail?
-                        event = event.copy(
-                                type = event.getClearType(),
-                                content = mapOf(
-                                        "chain_index" to fromIndex
-                                )
-                        )
-                )
-            }
-        }
-    }
-
-    fun onRoomKeyWithHeld(sessionId: String,
-                          algorithm: String,
-                          roomId: String,
-                          senderKey: String,
-                          fromDevice: String?,
-                          event: Event) {
-        outgoingRequestScope.launch {
-            sequencer.post {
-                Timber.tag(loggerTag.value).d("Withheld received for $sessionId from ${event.senderId}|$fromDevice")
-                Timber.tag(loggerTag.value).v("Withheld content ${event.getClearContent()}")
-
-                // We want to store withheld code from the sender of the message (owner of the megolm session), not from
-                // other devices that might gossip the key. If not the initial reason might be overridden
-                // by a request to one of our session.
-                event.getClearContent().toModel<RoomKeyWithHeldContent>()?.let { withheld ->
-                    withContext(coroutineDispatchers.crypto) {
-                        tryOrNull {
-                            deviceListManager.downloadKeys(listOf(event.senderId ?: ""), false)
-                        }
-                        cryptoStore.getUserDeviceList(event.senderId ?: "")
-                                .also { devices ->
-                                    Timber.tag(loggerTag.value)
-                                            .v("Withheld Devices for ${event.senderId} are ${devices.orEmpty().joinToString { it.identityKey() ?: "" }}")
-                                }
-                                ?.firstOrNull {
-                                    it.identityKey() == senderKey
-                                }
-                    }.also {
-                        Timber.tag(loggerTag.value).v("Withheld device for sender key $senderKey is from ${it?.shortDebugString()}")
-                    }?.let {
-                        if (it.userId == event.senderId) {
-                            if (fromDevice != null) {
-                                if (it.deviceId == fromDevice) {
-                                    Timber.tag(loggerTag.value).v("Storing sender Withheld code ${withheld.code} for ${withheld.sessionId}")
-                                    cryptoStore.addWithHeldMegolmSession(withheld)
-                                }
-                            } else {
-                                Timber.tag(loggerTag.value).v("Storing sender Withheld code ${withheld.code} for ${withheld.sessionId}")
-                                cryptoStore.addWithHeldMegolmSession(withheld)
-                            }
-                        }
-                    }
-                }
-
-                // Here we store the replies from a given request
-                cryptoStore.updateOutgoingRoomKeyReply(
-                        roomId = roomId,
-                        sessionId = sessionId,
-                        algorithm = algorithm,
-                        senderKey = senderKey,
-                        fromDevice = fromDevice,
-                        event = event
-                )
-            }
-        }
-    }
-
-    /**
-     * Should be called after a sync, ideally if no catchup sync needed (as keys might arrive in those)
-     */
-    fun requireProcessAllPendingKeyRequests() {
-        outgoingRequestScope.launch {
-            sequencer.post {
-                internalProcessPendingKeyRequests()
-            }
-        }
-    }
-
-    private fun internalQueueCancelRequest(sessionId: String, roomId: String, senderKey: String, localKnownChainIndex: Int) {
-        // do we have known requests for that session??
-        Timber.tag(loggerTag.value).v("Cancel Key Request if needed for $sessionId")
-        val knownRequest = cryptoStore.getOutgoingRoomKeyRequest(
-                algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
-                roomId = roomId,
-                sessionId = sessionId,
-                senderKey = senderKey
-        )
-        if (knownRequest.isEmpty()) return Unit.also {
-            Timber.tag(loggerTag.value).v("Handle Cancel Key Request for $sessionId -- Was not currently requested")
-        }
-        if (knownRequest.size > 1) {
-            // It's worth logging, there should be only one
-            Timber.tag(loggerTag.value).w("Found multiple requests for same sessionId $sessionId")
-        }
-        knownRequest.forEach { request ->
-            when (request.state) {
-                OutgoingRoomKeyRequestState.UNSENT                               -> {
-                    if (request.fromIndex >= localKnownChainIndex) {
-                        // we have a good index we can cancel
-                        cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
-                    }
-                }
-                OutgoingRoomKeyRequestState.SENT                                 -> {
-                    // It was already sent, and index satisfied we can cancel
-                    if (request.fromIndex >= localKnownChainIndex) {
-                        cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
-                    }
-                }
-                OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> {
-                    // It is already marked to be cancelled
-                }
-                OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
-                    if (request.fromIndex >= localKnownChainIndex) {
-                        // we just want to cancel now
-                        cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING)
-                    }
-                }
-                OutgoingRoomKeyRequestState.SENT_THEN_CANCELED                   -> {
-                    // was already canceled
-                    // if we need a better index, should we resend?
-                }
-            }
-        }
-    }
-
-    fun close() {
-        try {
-            outgoingRequestScope.cancel("User Terminate")
-            requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.clear()
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value).w("Failed to shutDown request manager")
-        }
-    }
-
-    private fun internalQueueRequest(requestBody: RoomKeyRequestBody, recipients: Map<String, List<String>>, fromIndex: Int, force: Boolean) {
-        if (!cryptoStore.isKeyGossipingEnabled()) {
-            // we might want to try backup?
-            if (requestBody.roomId != null && requestBody.sessionId != null) {
-                requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.push(requestBody.roomId to requestBody.sessionId)
-            }
-            Timber.tag(loggerTag.value).d("discarding request for ${requestBody.sessionId} as gossiping is disabled")
-            return
-        }
-
-        Timber.tag(loggerTag.value).d("Queueing key request for ${requestBody.sessionId} force:$force")
-        val existing = cryptoStore.getOutgoingRoomKeyRequest(requestBody)
-        Timber.tag(loggerTag.value).v("Queueing key request exiting is ${existing?.state}")
-        when (existing?.state) {
-            null                                                             -> {
-                // create a new one
-                cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
-            }
-            OutgoingRoomKeyRequestState.UNSENT                               -> {
-                // nothing it's new or not yet handled
-            }
-            OutgoingRoomKeyRequestState.SENT                                 -> {
-                // it was already requested
-                Timber.tag(loggerTag.value).d("The session ${requestBody.sessionId} is already requested")
-                if (force) {
-                    // update to UNSENT
-                    Timber.tag(loggerTag.value).d(".. force to request  ${requestBody.sessionId}")
-                    cryptoStore.updateOutgoingRoomKeyRequestState(existing.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND)
-                } else {
-                    if (existing.roomId != null && existing.sessionId != null) {
-                        requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.push(existing.roomId to existing.sessionId)
-                    }
-                }
-            }
-            OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> {
-                // request is canceled only if I got the keys so what to do here...
-                if (force) {
-                    cryptoStore.updateOutgoingRoomKeyRequestState(existing.requestId, OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND)
-                }
-            }
-            OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> {
-                // It's already going to resend
-            }
-            OutgoingRoomKeyRequestState.SENT_THEN_CANCELED                   -> {
-                if (force) {
-                    cryptoStore.deleteOutgoingRoomKeyRequest(existing.requestId)
-                    cryptoStore.getOrAddOutgoingRoomKeyRequest(requestBody, recipients, fromIndex)
-                }
-            }
-        }
-
-        if (existing != null && existing.fromIndex >= fromIndex) {
-            // update the required index
-            cryptoStore.updateOutgoingRoomKeyRequiredIndex(existing.requestId, fromIndex)
-        }
-    }
-
-    private suspend fun internalProcessPendingKeyRequests() {
-        val toProcess = cryptoStore.getOutgoingRoomKeyRequests(OutgoingRoomKeyRequestState.pendingStates())
-        Timber.tag(loggerTag.value).v("Processing all pending key requests (found ${toProcess.size} pending)")
-
-        measureTimeMillis {
-            toProcess.forEach {
-                when (it.state) {
-                    OutgoingRoomKeyRequestState.UNSENT                               -> handleUnsentRequest(it)
-                    OutgoingRoomKeyRequestState.CANCELLATION_PENDING                 -> handleRequestToCancel(it)
-                    OutgoingRoomKeyRequestState.CANCELLATION_PENDING_AND_WILL_RESEND -> handleRequestToCancelWillResend(it)
-                    OutgoingRoomKeyRequestState.SENT_THEN_CANCELED,
-                    OutgoingRoomKeyRequestState.SENT                                 -> {
-                        // these are filtered out
-                    }
-                }
-            }
-        }.let {
-            Timber.tag(loggerTag.value).v("Finish processing pending key request in $it ms")
-        }
-
-        val maxBackupCallsBySync = 60
-        var currentCalls = 0
-        measureTimeMillis {
-            while (requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.isNotEmpty() && currentCalls < maxBackupCallsBySync) {
-                requestDiscardedBecauseAlreadySentThatCouldBeTriedWithBackup.pop().let { (roomId, sessionId) ->
-                    // we want to rate limit that somehow :/
-                    perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId)
-                }
-                currentCalls++
-            }
-        }.let {
-            Timber.tag(loggerTag.value).v("Finish querying backup in $it ms")
-        }
-    }
-
-    private suspend fun handleUnsentRequest(request: OutgoingKeyRequest) {
-        // In order to avoid generating to_device traffic, we can first check if the key is backed up
-        Timber.tag(loggerTag.value).v("Handling unsent request for megolm session ${request.sessionId} in ${request.roomId}")
-        val sessionId = request.sessionId ?: return
-        val roomId = request.roomId ?: return
-        if (perSessionBackupQueryRateLimiter.tryFromBackupIfPossible(sessionId, roomId)) {
-            // let's see what's the index
-            val knownIndex = tryOrNull {
-                inboundGroupSessionStore.getInboundGroupSession(sessionId, request.requestBody?.senderKey ?: "")?.wrapper?.firstKnownIndex
-            }
-            if (knownIndex != null && knownIndex <= request.fromIndex) {
-                // we found the key in backup with good enough index, so we can just mark as cancelled, no need to send request
-                Timber.tag(loggerTag.value).v("Megolm session $sessionId successfully restored from backup, do not send request")
-                cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
-                return
-            }
-        }
-
-        // we need to send the request
-        val toDeviceContent = RoomKeyShareRequest(
-                requestingDeviceId = cryptoStore.getDeviceId(),
-                requestId = request.requestId,
-                action = GossipingToDeviceObject.ACTION_SHARE_REQUEST,
-                body = request.requestBody
-        )
-        val contentMap = MXUsersDevicesMap<Any>()
-        request.recipients.forEach { userToDeviceMap ->
-            userToDeviceMap.value.forEach { deviceId ->
-                contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
-            }
-        }
-
-        val params = SendToDeviceTask.Params(
-                eventType = EventType.ROOM_KEY_REQUEST,
-                contentMap = contentMap,
-                transactionId = request.requestId
-        )
-        try {
-            withContext(coroutineDispatchers.io) {
-                sendToDeviceTask.executeRetry(params, 3)
-            }
-            Timber.tag(loggerTag.value).d("Key request sent for $sessionId in room $roomId to ${request.recipients}")
-            // The request was sent, so update state
-            cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.SENT)
-            // TODO update the audit trail
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value).v("Failed to request $sessionId targets:${request.recipients}")
-        }
-    }
-
-    private suspend fun handleRequestToCancel(request: OutgoingKeyRequest): Boolean {
-        Timber.tag(loggerTag.value).v("handleRequestToCancel for megolm session ${request.sessionId}")
-        // we have to cancel this
-        val toDeviceContent = RoomKeyShareRequest(
-                requestingDeviceId = cryptoStore.getDeviceId(),
-                requestId = request.requestId,
-                action = GossipingToDeviceObject.ACTION_SHARE_CANCELLATION
-        )
-        val contentMap = MXUsersDevicesMap<Any>()
-        request.recipients.forEach { userToDeviceMap ->
-            userToDeviceMap.value.forEach { deviceId ->
-                contentMap.setObject(userToDeviceMap.key, deviceId, toDeviceContent)
-            }
-        }
-
-        val params = SendToDeviceTask.Params(
-                eventType = EventType.ROOM_KEY_REQUEST,
-                contentMap = contentMap,
-                transactionId = request.requestId
-        )
-        return try {
-            withContext(coroutineDispatchers.io) {
-                sendToDeviceTask.executeRetry(params, 3)
-            }
-            // The request cancellation was sent, we don't delete yet because we want
-            // to keep trace of the sent replies
-            cryptoStore.updateOutgoingRoomKeyRequestState(request.requestId, OutgoingRoomKeyRequestState.SENT_THEN_CANCELED)
-            true
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value).v("Failed to cancel request ${request.requestId} for session $sessionId targets:${request.recipients}")
-            false
-        }
-    }
-
-    private suspend fun handleRequestToCancelWillResend(request: OutgoingKeyRequest) {
-        if (handleRequestToCancel(request)) {
-            // this will create a new unsent request with no replies that will be process in the following call
-            cryptoStore.deleteOutgoingRoomKeyRequest(request.requestId)
-            request.requestBody?.let { cryptoStore.getOrAddOutgoingRoomKeyRequest(it, request.recipients, request.fromIndex) }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt
index 1872e33823..8fcdb4168b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PerSessionBackupQueryRateLimiter.kt
@@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
 import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
 import org.matrix.android.sdk.api.util.awaitCallback
+import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.util.time.Clock
 import timber.log.Timber
@@ -39,7 +40,7 @@ private val loggerTag = LoggerTag("OutgoingGossipingRequestManager", LoggerTag.C
  */
 internal class PerSessionBackupQueryRateLimiter @Inject constructor(
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val keysBackupService: Lazy<DefaultKeysBackupService>,
+        private val keysBackupService: Lazy<RustKeyBackupService>,
         private val cryptoStore: IMXCryptoStore,
         private val clock: Clock,
 ) {
@@ -103,16 +104,14 @@ internal class PerSessionBackupQueryRateLimiter @Inject constructor(
 
         val successfullyImported = withContext(coroutineDispatchers.io) {
             try {
-                awaitCallback<ImportRoomKeysResult> {
                     keysBackupService.get().restoreKeysWithRecoveryKey(
                             currentVersion,
                             savedKeyBackupKeyInfo?.recoveryKey ?: "",
                             roomId,
                             sessionId,
                             null,
-                            it
                     )
-                }.successfullyNumberOfImportedKeys
+                .successfullyNumberOfImportedKeys
             } catch (failure: Throwable) {
                 // Fail silently
                 Timber.tag(loggerTag.value).v("getFromBackup failed ${failure.localizedMessage}")
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt
new file mode 100644
index 0000000000..e2245a6e40
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/PrepareToEncryptUseCase.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto
+
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.joinAll
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.MXCryptoError
+import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
+import org.matrix.android.sdk.internal.crypto.network.RequestSender
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.session.room.membership.LoadRoomMembersTask
+import timber.log.Timber
+import uniffi.olm.Request
+import uniffi.olm.RequestType
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+
+private val loggerTag = LoggerTag("PrepareToEncryptUseCase", LoggerTag.CRYPTO)
+
+@SessionScope
+internal class PrepareToEncryptUseCase @Inject constructor(olmMachineProvider: OlmMachineProvider,
+                                                           private val coroutineDispatchers: MatrixCoroutineDispatchers,
+                                                           private val cryptoStore: IMXCryptoStore,
+                                                           private val getRoomUserIds: GetRoomUserIdsUseCase,
+                                                           private val requestSender: RequestSender,
+                                                           private val loadRoomMembersTask: LoadRoomMembersTask,
+                                                           private val keysBackupService: RustKeyBackupService
+) {
+
+    private val olmMachine = olmMachineProvider.olmMachine
+
+    private val keyClaimLock: Mutex = Mutex()
+    private val roomKeyShareLocks: ConcurrentHashMap<String, Mutex> = ConcurrentHashMap()
+
+    suspend operator fun invoke(roomId: String, ensureAllMembersAreLoaded: Boolean) {
+        withContext(coroutineDispatchers.crypto) {
+            Timber.tag(loggerTag.value).d("prepareToEncrypt() roomId:$roomId Check room members up to date")
+            // Ensure to load all room members
+            if (ensureAllMembersAreLoaded) {
+                try {
+                    loadRoomMembersTask.execute(LoadRoomMembersTask.Params(roomId))
+                } catch (failure: Throwable) {
+                    Timber.tag(loggerTag.value).e("prepareToEncrypt() : Failed to load room members")
+                    throw failure
+                }
+            }
+            val userIds = getRoomUserIds(roomId)
+            val algorithm = getEncryptionAlgorithm(roomId)
+            if (algorithm == null) {
+                val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, MXCryptoError.NO_MORE_ALGORITHM_REASON)
+                Timber.tag(loggerTag.value).e("prepareToEncrypt() : $reason")
+                throw IllegalArgumentException("Missing algorithm")
+            }
+            preshareRoomKey(roomId, userIds)
+        }
+    }
+
+    private fun getEncryptionAlgorithm(roomId: String): String? {
+        return cryptoStore.getRoomAlgorithm(roomId)
+    }
+
+    private suspend fun preshareRoomKey(roomId: String, roomMembers: List<String>) {
+        claimMissingKeys(roomMembers)
+        val keyShareLock = roomKeyShareLocks.getOrPut(roomId) { Mutex() }
+        var sharedKey = false
+        keyShareLock.withLock {
+            coroutineScope {
+                olmMachine.shareRoomKey(roomId, roomMembers).map {
+                    when (it) {
+                        is Request.ToDevice -> {
+                            sharedKey = true
+                            async {
+                                sendToDevice(it)
+                            }
+                        }
+                        else                -> {
+                            // This request can only be a to-device request but
+                            // we need to handle all our cases and put this
+                            // async block for our joinAll to work.
+                            async {}
+                        }
+                    }
+                }.joinAll()
+            }
+        }
+
+        // If we sent out a room key over to-device messages it's likely that we created a new one
+        // Try to back the key up
+        if (sharedKey) {
+            keysBackupService.maybeBackupKeys()
+        }
+    }
+
+    private suspend fun claimMissingKeys(roomMembers: List<String>) = keyClaimLock.withLock {
+        val request = this.olmMachine.getMissingSessions(roomMembers)
+        // This request can only be a keys claim request.
+        when (request) {
+            is Request.KeysClaim -> {
+                claimKeys(request)
+            }
+            else                 -> {
+            }
+        }
+    }
+
+    private suspend fun sendToDevice(request: Request.ToDevice) {
+        try {
+            requestSender.sendToDevice(request)
+            olmMachine.markRequestAsSent(request.requestId, RequestType.TO_DEVICE, "{}")
+        } catch (throwable: Throwable) {
+            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO sendToDevice(): error")
+        }
+    }
+
+    private suspend fun claimKeys(request: Request.KeysClaim) {
+        try {
+            val response = requestSender.claimKeys(request)
+            olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_CLAIM, response)
+        } catch (throwable: Throwable) {
+            Timber.tag(loggerTag.value).e(throwable, "## CRYPTO claimKeys(): error")
+        }
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt
index b6e5cdd8a2..63a1047451 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/QrCodeVerification.kt
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerification
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
-import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64
+import org.matrix.android.sdk.api.util.fromBase64
 import org.matrix.android.sdk.internal.crypto.network.RequestSender
 import org.matrix.android.sdk.internal.crypto.verification.UpdateDispatcher
 import uniffi.olm.CryptoStoreException
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
deleted file mode 100644
index 7a4f08fe8e..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomDecryptorProvider.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
-import org.matrix.android.sdk.api.session.crypto.NewSessionListener
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXDecrypting
-import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmDecryptionFactory
-import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmDecryptionFactory
-import org.matrix.android.sdk.internal.session.SessionScope
-import timber.log.Timber
-import javax.inject.Inject
-
-@SessionScope
-internal class RoomDecryptorProvider @Inject constructor(
-        private val olmDecryptionFactory: MXOlmDecryptionFactory,
-        private val megolmDecryptionFactory: MXMegolmDecryptionFactory
-) {
-
-    // A map from algorithm to MXDecrypting instance, for each room
-    private val roomDecryptors: MutableMap<String /* room id */, MutableMap<String /* algorithm */, IMXDecrypting>> = HashMap()
-
-    private val newSessionListeners = ArrayList<NewSessionListener>()
-
-    fun addNewSessionListener(listener: NewSessionListener) {
-        if (!newSessionListeners.contains(listener)) newSessionListeners.add(listener)
-    }
-
-    fun removeSessionListener(listener: NewSessionListener) {
-        newSessionListeners.remove(listener)
-    }
-
-    /**
-     * Get a decryptor for a given room and algorithm.
-     * If we already have a decryptor for the given room and algorithm, return
-     * it. Otherwise try to instantiate it.
-     *
-     * @param roomId    the room id
-     * @param algorithm the crypto algorithm
-     * @return the decryptor
-     * // TODO Create another method for the case of roomId is null
-     */
-    fun getOrCreateRoomDecryptor(roomId: String?, algorithm: String?): IMXDecrypting? {
-        // sanity check
-        if (algorithm.isNullOrEmpty()) {
-            Timber.e("## getRoomDecryptor() : null algorithm")
-            return null
-        }
-        if (roomId != null && roomId.isNotEmpty()) {
-            synchronized(roomDecryptors) {
-                val decryptors = roomDecryptors.getOrPut(roomId) { mutableMapOf() }
-                val alg = decryptors[algorithm]
-                if (alg != null) {
-                    return alg
-                }
-            }
-        }
-        val decryptingClass = MXCryptoAlgorithms.hasDecryptorClassForAlgorithm(algorithm)
-        if (decryptingClass) {
-            val alg = when (algorithm) {
-                MXCRYPTO_ALGORITHM_MEGOLM -> megolmDecryptionFactory.create().apply {
-                    this.newSessionListener = object : NewSessionListener {
-                        override fun onNewSession(roomId: String?, sessionId: String) {
-                            // PR reviewer: the parameter has been renamed so is now in conflict with the parameter of getOrCreateRoomDecryptor
-                            newSessionListeners.toList().forEach {
-                                try {
-                                    it.onNewSession(roomId, sessionId)
-                                } catch (e: Throwable) {
-                                }
-                            }
-                        }
-                    }
-                }
-                else                      -> olmDecryptionFactory.create()
-            }
-            if (!roomId.isNullOrEmpty()) {
-                synchronized(roomDecryptors) {
-                    roomDecryptors[roomId]?.put(algorithm, alg)
-                }
-            }
-            return alg
-        }
-        return null
-    }
-
-    fun getRoomDecryptor(roomId: String?, algorithm: String?): IMXDecrypting? {
-        if (roomId == null || algorithm == null) {
-            return null
-        }
-        return roomDecryptors[roomId]?.get(algorithm)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
deleted file mode 100644
index 1a8c160d9c..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RoomEncryptorsStore.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto
-
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_OLM
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
-import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
-import org.matrix.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.session.SessionScope
-import javax.inject.Inject
-
-@SessionScope
-internal class RoomEncryptorsStore @Inject constructor(
-        private val cryptoStore: IMXCryptoStore,
-        private val megolmEncryptionFactory: MXMegolmEncryptionFactory,
-        private val olmEncryptionFactory: MXOlmEncryptionFactory,
-) {
-
-    // MXEncrypting instance for each room.
-    private val roomEncryptors = mutableMapOf<String, IMXEncrypting>()
-
-    fun put(roomId: String, alg: IMXEncrypting) {
-        synchronized(roomEncryptors) {
-            roomEncryptors.put(roomId, alg)
-        }
-    }
-
-    fun get(roomId: String): IMXEncrypting? {
-        return synchronized(roomEncryptors) {
-            val cache = roomEncryptors[roomId]
-            if (cache != null) {
-                return@synchronized cache
-            } else {
-                val alg: IMXEncrypting? = when (cryptoStore.getRoomAlgorithm(roomId)) {
-                    MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
-                    MXCRYPTO_ALGORITHM_OLM    -> olmEncryptionFactory.create(roomId)
-                    else                      -> null
-                }
-                alg?.let { roomEncryptors.put(roomId, it) }
-                return@synchronized alg
-            }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt
index f20034e9c1..68ec92ab98 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/RustCrossSigningService.kt
@@ -18,15 +18,15 @@ package org.matrix.android.sdk.internal.crypto
 
 import kotlinx.coroutines.flow.Flow
 import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
-import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
 import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
+import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustResult
 import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
+import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
+import org.matrix.android.sdk.api.session.crypto.crosssigning.UserTrustResult
+import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
+import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
 import org.matrix.android.sdk.api.util.Optional
-import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustResult
-import org.matrix.android.sdk.internal.crypto.crosssigning.UserTrustResult
-import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified
-import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
 import org.matrix.android.sdk.internal.di.UserId
 import javax.inject.Inject
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
index 6fb6914206..3ef5a963f1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/SecretShareManager.kt
@@ -24,11 +24,6 @@ import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
 import org.matrix.android.sdk.api.auth.data.Credentials
 import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
-import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
 import org.matrix.android.sdk.api.session.crypto.keyshare.GossipingRequestListener
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
 import org.matrix.android.sdk.api.session.crypto.model.SecretShareRequest
@@ -36,9 +31,6 @@ import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.content.SecretSendEventContent
 import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.api.util.toBase64NoPadding
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
 import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId
@@ -54,8 +46,6 @@ internal class SecretShareManager @Inject constructor(
         private val credentials: Credentials,
         private val cryptoStore: IMXCryptoStore,
         private val cryptoCoroutineScope: CoroutineScope,
-        private val messageEncrypter: MessageEncrypter,
-        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
         private val sendToDeviceTask: SendToDeviceTask,
         private val coroutineDispatchers: MatrixCoroutineDispatchers,
         private val clock: Clock,
@@ -107,6 +97,7 @@ internal class SecretShareManager @Inject constructor(
         }
     }
 
+    /*
     suspend fun handleSecretRequest(toDevice: Event) {
         val request = toDevice.getClearContent().toModel<SecretShareRequest>()
                 ?: return Unit.also {
@@ -214,6 +205,8 @@ internal class SecretShareManager @Inject constructor(
         }
     }
 
+     */
+
     private suspend fun hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId: String): Boolean {
         val verifTimestamp = verifMutex.withLock {
             recentlyVerifiedDevices[deviceId]
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ShouldEncryptForInvitedMembersUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ShouldEncryptForInvitedMembersUseCase.kt
new file mode 100644
index 0000000000..51e373b1d9
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/ShouldEncryptForInvitedMembersUseCase.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.internal.crypto
+
+import org.matrix.android.sdk.api.crypto.MXCryptoConfig
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import javax.inject.Inject
+
+internal class ShouldEncryptForInvitedMembersUseCase @Inject constructor(private val cryptoConfig: MXCryptoConfig,
+                                                                         private val cryptoStore: IMXCryptoStore) {
+
+    operator fun invoke(roomId: String): Boolean {
+        return cryptoConfig.enableEncryptionForInvitedMembers && cryptoStore.shouldEncryptForInvitedMembers(roomId)
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt
index 3cc94dae86..3d0c42b878 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/UserIdentities.kt
@@ -18,11 +18,11 @@ package org.matrix.android.sdk.internal.crypto
 
 import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
+import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
 import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.internal.crypto.model.CryptoCrossSigningKey
 import org.matrix.android.sdk.internal.crypto.network.RequestSender
 import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
 import uniffi.olm.CryptoStoreException
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt
index 9c1b892bfd..aec2495fc7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt
@@ -27,7 +27,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.ValidVerificationI
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
 import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
 import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf
-import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding
+import org.matrix.android.sdk.api.util.toBase64NoPadding
 import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN
 import org.matrix.android.sdk.internal.crypto.network.RequestSender
 import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt
deleted file mode 100644
index df29a494db..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForDevicesAction.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.actions
-
-import kotlinx.coroutines.sync.Mutex
-import kotlinx.coroutines.sync.withLock
-import kotlinx.coroutines.withContext
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.model.MXKey
-import org.matrix.android.sdk.internal.crypto.model.MXOlmSessionResult
-import org.matrix.android.sdk.internal.crypto.tasks.ClaimOneTimeKeysForUsersDeviceTask
-import org.matrix.android.sdk.internal.session.SessionScope
-import timber.log.Timber
-import javax.inject.Inject
-
-private const val ONE_TIME_KEYS_RETRY_COUNT = 3
-
-private val loggerTag = LoggerTag("EnsureOlmSessionsForDevicesAction", LoggerTag.CRYPTO)
-
-@SessionScope
-internal class EnsureOlmSessionsForDevicesAction @Inject constructor(
-        private val olmDevice: MXOlmDevice,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val oneTimeKeysForUsersDeviceTask: ClaimOneTimeKeysForUsersDeviceTask) {
-
-    private val ensureMutex = Mutex()
-
-    /**
-     * We want to synchronize a bit here, because we are iterating to check existing olm session and
-     * also adding some
-     */
-    suspend fun handle(devicesByUser: Map<String, List<CryptoDeviceInfo>>, force: Boolean = false): MXUsersDevicesMap<MXOlmSessionResult> {
-        ensureMutex.withLock {
-            val results = MXUsersDevicesMap<MXOlmSessionResult>()
-            val deviceList = devicesByUser.flatMap { it.value }
-            Timber.tag(loggerTag.value)
-                    .d("ensure olm forced:$force for ${deviceList.joinToString { it.shortDebugString() }}")
-            val devicesToCreateSessionWith = mutableListOf<CryptoDeviceInfo>()
-            if (force) {
-                // we take all devices and will query otk for them
-                devicesToCreateSessionWith.addAll(deviceList)
-            } else {
-                // only peek devices without active session
-                deviceList.forEach { deviceInfo ->
-                    val deviceId = deviceInfo.deviceId
-                    val userId = deviceInfo.userId
-                    val key = deviceInfo.identityKey() ?: return@forEach Unit.also {
-                        Timber.tag(loggerTag.value).w("Ignoring device ${deviceInfo.shortDebugString()} without identity key")
-                    }
-
-                    // is there a session that as been already used?
-                    val sessionId = olmDevice.getSessionId(key)
-                    if (sessionId.isNullOrEmpty()) {
-                        Timber.tag(loggerTag.value).d("Found no existing olm session ${deviceInfo.shortDebugString()} add to claim list")
-                        devicesToCreateSessionWith.add(deviceInfo)
-                    } else {
-                        Timber.tag(loggerTag.value).d("using olm session $sessionId for (${deviceInfo.userId}|$deviceId)")
-                        val olmSessionResult = MXOlmSessionResult(deviceInfo, sessionId)
-                        results.setObject(userId, deviceId, olmSessionResult)
-                    }
-                }
-            }
-
-            if (devicesToCreateSessionWith.isEmpty()) {
-                // no session to create
-                return results
-            }
-            val usersDevicesToClaim = MXUsersDevicesMap<String>().apply {
-                devicesToCreateSessionWith.forEach {
-                    setObject(it.userId, it.deviceId, MXKey.KEY_SIGNED_CURVE_25519_TYPE)
-                }
-            }
-
-            // Let's now claim one time keys
-            val claimParams = ClaimOneTimeKeysForUsersDeviceTask.Params(usersDevicesToClaim)
-            val oneTimeKeys = withContext(coroutineDispatchers.io) {
-                oneTimeKeysForUsersDeviceTask.executeRetry(claimParams, ONE_TIME_KEYS_RETRY_COUNT)
-            }
-
-            // let now start olm session using the new otks
-            devicesToCreateSessionWith.forEach { deviceInfo ->
-                val userId = deviceInfo.userId
-                val deviceId = deviceInfo.deviceId
-                // Did we get an OTK
-                val oneTimeKey = oneTimeKeys.getObject(userId, deviceId)
-                if (oneTimeKey == null) {
-                    Timber.tag(loggerTag.value).d("No otk for ${deviceInfo.shortDebugString()}")
-                } else if (oneTimeKey.type != MXKey.KEY_SIGNED_CURVE_25519_TYPE) {
-                    Timber.tag(loggerTag.value).d("Bad otk type (${oneTimeKey.type}) for ${deviceInfo.shortDebugString()}")
-                } else {
-                    val olmSessionId = verifyKeyAndStartSession(oneTimeKey, userId, deviceInfo)
-                    if (olmSessionId != null) {
-                        val olmSessionResult = MXOlmSessionResult(deviceInfo, olmSessionId)
-                        results.setObject(userId, deviceId, olmSessionResult)
-                    } else {
-                        Timber
-                                .tag(loggerTag.value)
-                                .d("## CRYPTO | cant unwedge failed to create outbound ${deviceInfo.shortDebugString()}")
-                    }
-                }
-            }
-            return results
-        }
-    }
-
-    private fun verifyKeyAndStartSession(oneTimeKey: MXKey, userId: String, deviceInfo: CryptoDeviceInfo): String? {
-        var sessionId: String? = null
-
-        val deviceId = deviceInfo.deviceId
-        val signKeyId = "ed25519:$deviceId"
-        val signature = oneTimeKey.signatureForUserId(userId, signKeyId)
-
-        val fingerprint = deviceInfo.fingerprint()
-        if (!signature.isNullOrEmpty() && !fingerprint.isNullOrEmpty()) {
-            var isVerified = false
-            var errorMessage: String? = null
-
-            try {
-                olmDevice.verifySignature(fingerprint, oneTimeKey.signalableJSONDictionary(), signature)
-                isVerified = true
-            } catch (e: Exception) {
-                Timber.tag(loggerTag.value).d(
-                        e, "verifyKeyAndStartSession() : Verify error for otk: ${oneTimeKey.signalableJSONDictionary()}," +
-                        " signature:$signature fingerprint:$fingerprint"
-                )
-                Timber.tag(loggerTag.value).e(
-                        "verifyKeyAndStartSession() : Verify error for ${deviceInfo.userId}|${deviceInfo.deviceId} " +
-                                " - signable json ${oneTimeKey.signalableJSONDictionary()}"
-                )
-                errorMessage = e.message
-            }
-
-            // Check one-time key signature
-            if (isVerified) {
-                sessionId = deviceInfo.identityKey()?.let { identityKey ->
-                    olmDevice.createOutboundSession(identityKey, oneTimeKey.value)
-                }
-
-                if (sessionId.isNullOrEmpty()) {
-                    // Possibly a bad key
-                    Timber.tag(loggerTag.value).e("verifyKeyAndStartSession() : Error starting session with device $userId:$deviceId")
-                } else {
-                    Timber.tag(loggerTag.value).d("verifyKeyAndStartSession() : Started new sessionId $sessionId for device $userId:$deviceId")
-                }
-            } else {
-                Timber.tag(loggerTag.value).e("verifyKeyAndStartSession() : Unable to verify otk signature for $userId:$deviceId: $errorMessage")
-            }
-        }
-
-        return sessionId
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt
deleted file mode 100644
index fc211537a6..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/EnsureOlmSessionsForUsersAction.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.actions
-
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.model.MXOlmSessionResult
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import timber.log.Timber
-import javax.inject.Inject
-
-internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                                   private val cryptoStore: IMXCryptoStore,
-                                                                   private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) {
-
-    /**
-     * Try to make sure we have established olm sessions for the given users.
-     * @param users    a list of user ids.
-     */
-    suspend fun handle(users: List<String>): MXUsersDevicesMap<MXOlmSessionResult> {
-        Timber.v("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users")
-        val devicesByUser = users.associateWith { userId ->
-            val devices = cryptoStore.getUserDevices(userId)?.values.orEmpty()
-
-            devices.filter {
-                // Don't bother setting up session to ourself
-                it.identityKey() != olmDevice.deviceCurve25519Key &&
-                        // Don't bother setting up sessions with blocked users
-                        !(it.trustLevel?.isVerified() ?: false)
-            }
-        }
-        return ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
deleted file mode 100644
index 22c4e59b18..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MegolmSessionDataImporter.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.actions
-
-import androidx.annotation.WorkerThread
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.listeners.ProgressListener
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.MegolmSessionData
-import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
-import org.matrix.android.sdk.internal.crypto.RoomDecryptorProvider
-import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXMegolmDecryption
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
-import javax.inject.Inject
-
-private val loggerTag = LoggerTag("MegolmSessionDataImporter", LoggerTag.CRYPTO)
-
-internal class MegolmSessionDataImporter @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                             private val roomDecryptorProvider: RoomDecryptorProvider,
-                                                             private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
-                                                             private val cryptoStore: IMXCryptoStore,
-                                                             private val clock: Clock,
-) {
-
-    /**
-     * Import a list of megolm session keys.
-     * Must be call on the crypto coroutine thread
-     *
-     * @param megolmSessionsData megolm sessions.
-     * @param fromBackup         true if the imported keys are already backed up on the server.
-     * @param progressListener   the progress listener
-     * @return import room keys result
-     */
-    @WorkerThread
-    fun handle(megolmSessionsData: List<MegolmSessionData>,
-               fromBackup: Boolean,
-               progressListener: ProgressListener?): ImportRoomKeysResult {
-        val t0 = clock.epochMillis()
-
-        val totalNumbersOfKeys = megolmSessionsData.size
-        var lastProgress = 0
-        var totalNumbersOfImportedKeys = 0
-
-        progressListener?.onProgress(0, 100)
-        val olmInboundGroupSessionWrappers = olmDevice.importInboundGroupSessions(megolmSessionsData)
-
-        megolmSessionsData.forEachIndexed { cpt, megolmSessionData ->
-            val decrypting = roomDecryptorProvider.getOrCreateRoomDecryptor(megolmSessionData.roomId, megolmSessionData.algorithm)
-
-            if (null != decrypting) {
-                try {
-                    val sessionId = megolmSessionData.sessionId
-                    Timber.tag(loggerTag.value).v("## importRoomKeys retrieve senderKey ${megolmSessionData.senderKey} sessionId $sessionId")
-
-                    totalNumbersOfImportedKeys++
-
-                    // cancel any outstanding room key requests for this session
-
-                    Timber.tag(loggerTag.value).d("Imported megolm session $sessionId from backup=$fromBackup in ${megolmSessionData.roomId}")
-                    outgoingKeyRequestManager.postCancelRequestForSessionIfNeeded(
-                            megolmSessionData.sessionId ?: "",
-                            megolmSessionData.roomId ?: "",
-                            megolmSessionData.senderKey ?: "",
-                            tryOrNull {
-                                olmInboundGroupSessionWrappers
-                                        .firstOrNull { it.olmInboundGroupSession?.sessionIdentifier() == megolmSessionData.sessionId }
-                                        ?.firstKnownIndex?.toInt()
-                            } ?: 0
-                    )
-
-                    // Have another go at decrypting events sent with this session
-                    when (decrypting) {
-                        is MXMegolmDecryption -> {
-                            decrypting.onNewSession(megolmSessionData.roomId, megolmSessionData.senderKey!!, sessionId!!)
-                        }
-                    }
-                } catch (e: Exception) {
-                    Timber.tag(loggerTag.value).e(e, "## importRoomKeys() : onNewSession failed")
-                }
-            }
-
-            if (progressListener != null) {
-                val progress = 100 * (cpt + 1) / totalNumbersOfKeys
-
-                if (lastProgress != progress) {
-                    lastProgress = progress
-
-                    progressListener.onProgress(progress, 100)
-                }
-            }
-        }
-
-        // Do not back up the key if it comes from a backup recovery
-        if (fromBackup) {
-            cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
-        }
-
-        val t1 = clock.epochMillis()
-
-        Timber.tag(loggerTag.value).v("## importMegolmSessionsData : sessions import " + (t1 - t0) + " ms (" + megolmSessionsData.size + " sessions)")
-
-        return ImportRoomKeysResult(totalNumbersOfKeys, totalNumbersOfImportedKeys)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt
deleted file mode 100644
index 9bbbab4992..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/MessageEncrypter.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.actions
-
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_OLM
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.events.model.Content
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedMessage
-import org.matrix.android.sdk.internal.di.DeviceId
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.util.JsonCanonicalizer
-import org.matrix.android.sdk.internal.util.convertToUTF8
-import timber.log.Timber
-import javax.inject.Inject
-
-private val loggerTag = LoggerTag("MessageEncrypter", LoggerTag.CRYPTO)
-
-internal class MessageEncrypter @Inject constructor(
-        @UserId
-        private val userId: String,
-        @DeviceId
-        private val deviceId: String?,
-        private val olmDevice: MXOlmDevice) {
-    /**
-     * Encrypt an event payload for a list of devices.
-     * This method must be called from the getCryptoHandler() thread.
-     *
-     * @param payloadFields fields to include in the encrypted payload.
-     * @param deviceInfos   list of device infos to encrypt for.
-     * @return the content for an m.room.encrypted event.
-     */
-    suspend fun encryptMessage(payloadFields: Content, deviceInfos: List<CryptoDeviceInfo>): EncryptedMessage {
-        val deviceInfoParticipantKey = deviceInfos.associateBy { it.identityKey()!! }
-
-        val payloadJson = payloadFields.toMutableMap()
-
-        payloadJson["sender"] = userId
-        payloadJson["sender_device"] = deviceId!!
-
-        // Include the Ed25519 key so that the recipient knows what
-        // device this message came from.
-        // We don't need to include the curve25519 key since the
-        // recipient will already know this from the olm headers.
-        // When combined with the device keys retrieved from the
-        // homeserver signed by the ed25519 key this proves that
-        // the curve25519 key and the ed25519 key are owned by
-        // the same device.
-        payloadJson["keys"] = mapOf("ed25519" to olmDevice.deviceEd25519Key!!)
-
-        val ciphertext = mutableMapOf<String, Any>()
-
-        for ((deviceKey, deviceInfo) in deviceInfoParticipantKey) {
-            val sessionId = olmDevice.getSessionId(deviceKey)
-
-            if (!sessionId.isNullOrEmpty()) {
-                Timber.tag(loggerTag.value).d("Using sessionid $sessionId for device $deviceKey")
-
-                payloadJson["recipient"] = deviceInfo.userId
-                payloadJson["recipient_keys"] = mapOf("ed25519" to deviceInfo.fingerprint()!!)
-
-                val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
-                ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId, payloadString)!!
-            }
-        }
-
-        return EncryptedMessage(
-                algorithm = MXCRYPTO_ALGORITHM_OLM,
-                senderKey = olmDevice.deviceCurve25519Key,
-                cipherText = ciphertext
-        )
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt
deleted file mode 100644
index a1b1766de6..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/actions/SetDeviceVerificationAction.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.actions
-
-import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.di.UserId
-import timber.log.Timber
-import javax.inject.Inject
-
-internal class SetDeviceVerificationAction @Inject constructor(
-        private val cryptoStore: IMXCryptoStore,
-        @UserId private val userId: String,
-        private val defaultKeysBackupService: DefaultKeysBackupService) {
-
-    fun handle(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) {
-        val device = cryptoStore.getUserDevice(userId, deviceId)
-
-        // Sanity check
-        if (null == device) {
-            Timber.w("## setDeviceVerification() : Unknown device $userId:$deviceId")
-            return
-        }
-
-        if (device.isVerified != trustLevel.isVerified()) {
-            if (userId == this.userId) {
-                // If one of the user's own devices is being marked as verified / unverified,
-                // check the key backup status, since whether or not we use this depends on
-                // whether it has a signature from a verified device
-                defaultKeysBackupService.checkAndStartKeysBackup()
-            }
-        }
-
-        if (device.trustLevel != trustLevel) {
-            device.trustLevel = trustLevel
-            cryptoStore.setDeviceTrust(userId, deviceId, trustLevel.crossSigningVerified, trustLevel.locallyVerified)
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt
deleted file mode 100644
index 72eae066c9..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXDecrypting.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms
-
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
-import org.matrix.android.sdk.api.session.events.model.Event
-
-/**
- * An interface for decrypting data
- */
-internal interface IMXDecrypting {
-
-    /**
-     * Decrypt an event
-     *
-     * @param event    the raw event.
-     * @param timeline the id of the timeline where the event is decrypted. It is used to prevent replay attack.
-     * @return the decryption information, or an error
-     */
-    @Throws(MXCryptoError::class)
-    suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult
-
-    /**
-     * Handle a key event.
-     *
-     * @param event the key event.
-     */
-    fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {}
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
deleted file mode 100644
index b0f411cbcc..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXEncrypting.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms
-
-import org.matrix.android.sdk.api.session.events.model.Content
-
-/**
- * An interface for encrypting data
- */
-@Deprecated("rust")
-internal interface IMXEncrypting {
-
-    /**
-     * Encrypt an event content according to the configuration of the room.
-     *
-     * @param eventContent the content of the event.
-     * @param eventType    the type of the event.
-     * @param userIds      the room members the event will be sent to.
-     * @return the encrypted content
-     */
-    suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt
deleted file mode 100644
index 19d2ade788..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/IMXGroupEncryption.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms
-
-@Deprecated("rust")
-internal interface IMXGroupEncryption {
-
-    /**
-     * In Megolm, each recipient maintains a record of the ratchet value which allows
-     * them to decrypt any messages sent in the session after the corresponding point
-     * in the conversation. If this value is compromised, an attacker can similarly
-     * decrypt past messages which were encrypted by a key derived from the
-     * compromised or subsequent ratchet values. This gives 'partial' forward
-     * secrecy.
-     *
-     * To mitigate this issue, the application should offer the user the option to
-     * discard historical conversations, by winding forward any stored ratchet values,
-     * or discarding sessions altogether.
-     */
-    fun discardSessionKey()
-
-    suspend fun preshareKey(userIds: List<String>)
-
-    /**
-     * Re-shares a session key with devices if the key has already been
-     * sent to them.
-     *
-     * @param sessionId The id of the outbound session to share.
-     * @param userId The id of the user who owns the target device.
-     * @param deviceId The id of the target device.
-     * @param senderKey The key of the originating device for the session.
-     *
-     * @return true in case of success
-     */
-    suspend fun reshareKey(groupSessionId: String,
-                           userId: String,
-                           deviceId: String,
-                           senderKey: String): Boolean
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
deleted file mode 100644
index e808e18e76..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.megolm
-
-import dagger.Lazy
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.NewSessionListener
-import org.matrix.android.sdk.api.session.crypto.model.ForwardedRoomKeyContent
-import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXDecrypting
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.session.StreamEventsManager
-import timber.log.Timber
-
-private val loggerTag = LoggerTag("MXMegolmDecryption", LoggerTag.CRYPTO)
-
-internal class MXMegolmDecryption(
-        private val olmDevice: MXOlmDevice,
-        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
-        private val cryptoStore: IMXCryptoStore,
-        private val liveEventManager: Lazy<StreamEventsManager>
-) : IMXDecrypting {
-
-    var newSessionListener: NewSessionListener? = null
-
-    /**
-     * Events which we couldn't decrypt due to unknown sessions / indexes: map from
-     * senderKey|sessionId to timelines to list of MatrixEvents.
-     */
-//    private var pendingEvents: MutableMap<String /* senderKey|sessionId */, MutableMap<String /* timelineId */, MutableList<Event>>> = HashMap()
-
-    @Throws(MXCryptoError::class)
-    override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
-        return decryptEvent(event, timeline, true)
-    }
-
-    @Throws(MXCryptoError::class)
-    private suspend fun decryptEvent(event: Event, timeline: String, requestKeysOnFail: Boolean): MXEventDecryptionResult {
-        Timber.tag(loggerTag.value).v("decryptEvent ${event.eventId}, requestKeysOnFail:$requestKeysOnFail")
-        if (event.roomId.isNullOrBlank()) {
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
-        }
-
-        val encryptedEventContent = event.content.toModel<EncryptedEventContent>()
-                ?: throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
-
-        if (encryptedEventContent.senderKey.isNullOrBlank() ||
-                encryptedEventContent.sessionId.isNullOrBlank() ||
-                encryptedEventContent.ciphertext.isNullOrBlank()) {
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
-        }
-
-        return runCatching {
-            olmDevice.decryptGroupMessage(
-                    encryptedEventContent.ciphertext,
-                    event.roomId,
-                    timeline,
-                    encryptedEventContent.sessionId,
-                    encryptedEventContent.senderKey
-            )
-        }
-                .fold(
-                        { olmDecryptionResult ->
-                            // the decryption succeeds
-                            if (olmDecryptionResult.payload != null) {
-                                MXEventDecryptionResult(
-                                        clearEvent = olmDecryptionResult.payload,
-                                        senderCurve25519Key = olmDecryptionResult.senderKey,
-                                        claimedEd25519Key = olmDecryptionResult.keysClaimed?.get("ed25519"),
-                                        forwardingCurve25519KeyChain = olmDecryptionResult.forwardingCurve25519KeyChain
-                                                .orEmpty()
-                                ).also {
-                                    liveEventManager.get().dispatchLiveEventDecrypted(event, it)
-                                }
-                            } else {
-                                throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON)
-                            }
-                        },
-                        { throwable ->
-                            liveEventManager.get().dispatchLiveEventDecryptionFailed(event, throwable)
-                            if (throwable is MXCryptoError.OlmError) {
-                                // TODO Check the value of .message
-                                if (throwable.olmException.message == "UNKNOWN_MESSAGE_INDEX") {
-                                    // So we know that session, but it's ratcheted and we can't decrypt at that index
-
-                                    if (requestKeysOnFail) {
-                                        requestKeysForEvent(event)
-                                    }
-                                    // Check if partially withheld
-                                    val withHeldInfo = cryptoStore.getWithHeldMegolmSession(event.roomId, encryptedEventContent.sessionId)
-                                    if (withHeldInfo != null) {
-                                        // Encapsulate as withHeld exception
-                                        throw MXCryptoError.Base(
-                                                MXCryptoError.ErrorType.KEYS_WITHHELD,
-                                                withHeldInfo.code?.value ?: "",
-                                                withHeldInfo.reason
-                                        )
-                                    }
-
-                                    throw MXCryptoError.Base(
-                                            MXCryptoError.ErrorType.UNKNOWN_MESSAGE_INDEX,
-                                            "UNKNOWN_MESSAGE_INDEX",
-                                            null
-                                    )
-                                }
-
-                                val reason = String.format(MXCryptoError.OLM_REASON, throwable.olmException.message)
-                                val detailedReason = String.format(MXCryptoError.DETAILED_OLM_REASON, encryptedEventContent.ciphertext, reason)
-
-                                throw MXCryptoError.Base(
-                                        MXCryptoError.ErrorType.OLM,
-                                        reason,
-                                        detailedReason
-                                )
-                            }
-                            if (throwable is MXCryptoError.Base) {
-                                if (throwable.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) {
-                                    // Check if it was withheld by sender to enrich error code
-                                    val withHeldInfo = cryptoStore.getWithHeldMegolmSession(event.roomId, encryptedEventContent.sessionId)
-                                    if (withHeldInfo != null) {
-                                        if (requestKeysOnFail) {
-                                            requestKeysForEvent(event)
-                                        }
-                                        // Encapsulate as withHeld exception
-                                        throw MXCryptoError.Base(
-                                                MXCryptoError.ErrorType.KEYS_WITHHELD,
-                                                withHeldInfo.code?.value ?: "",
-                                                withHeldInfo.reason)
-                                    }
-
-                                    if (requestKeysOnFail) {
-                                        requestKeysForEvent(event)
-                                    }
-                                }
-                            }
-                            throw throwable
-                        }
-                )
-    }
-
-    /**
-     * Helper for the real decryptEvent and for _retryDecryption. If
-     * requestKeysOnFail is true, we'll send an m.room_key_request when we fail
-     * to decrypt the event due to missing megolm keys.
-     *
-     * @param event the event
-     */
-    private fun requestKeysForEvent(event: Event) {
-        outgoingKeyRequestManager.requestKeyForEvent(event, false)
-    }
-
-    /**
-     * Handle a key event.
-     *
-     * @param event the key event.
-     */
-    override fun onRoomKeyEvent(event: Event, defaultKeysBackupService: DefaultKeysBackupService) {
-        Timber.tag(loggerTag.value).v("onRoomKeyEvent()")
-        var exportFormat = false
-        val roomKeyContent = event.getClearContent().toModel<RoomKeyContent>() ?: return
-
-        var senderKey: String? = event.getSenderKey()
-        var keysClaimed: MutableMap<String, String> = HashMap()
-        val forwardingCurve25519KeyChain: MutableList<String> = ArrayList()
-
-        if (roomKeyContent.roomId.isNullOrEmpty() || roomKeyContent.sessionId.isNullOrEmpty() || roomKeyContent.sessionKey.isNullOrEmpty()) {
-            Timber.tag(loggerTag.value).e("onRoomKeyEvent() :  Key event is missing fields")
-            return
-        }
-        if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
-            if (!cryptoStore.isKeyGossipingEnabled()) {
-                Timber.tag(loggerTag.value)
-                        .i("onRoomKeyEvent(), ignore forward adding as per crypto config : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
-                return
-            }
-            Timber.tag(loggerTag.value).i("onRoomKeyEvent(), forward adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
-            val forwardedRoomKeyContent = event.getClearContent().toModel<ForwardedRoomKeyContent>()
-                    ?: return
-
-            forwardedRoomKeyContent.forwardingCurve25519KeyChain?.let {
-                forwardingCurve25519KeyChain.addAll(it)
-            }
-
-            if (senderKey == null) {
-                Timber.tag(loggerTag.value).e("onRoomKeyEvent() : event is missing sender_key field")
-                return
-            }
-
-            forwardingCurve25519KeyChain.add(senderKey)
-
-            exportFormat = true
-            senderKey = forwardedRoomKeyContent.senderKey
-            if (null == senderKey) {
-                Timber.tag(loggerTag.value).e("onRoomKeyEvent() : forwarded_room_key event is missing sender_key field")
-                return
-            }
-
-            if (null == forwardedRoomKeyContent.senderClaimedEd25519Key) {
-                Timber.tag(loggerTag.value).e("forwarded_room_key_event is missing sender_claimed_ed25519_key field")
-                return
-            }
-
-            keysClaimed["ed25519"] = forwardedRoomKeyContent.senderClaimedEd25519Key
-        } else {
-            Timber.tag(loggerTag.value).i("onRoomKeyEvent(), Adding key : ${roomKeyContent.roomId}|${roomKeyContent.sessionId}")
-            if (null == senderKey) {
-                Timber.tag(loggerTag.value).e("## onRoomKeyEvent() : key event has no sender key (not encrypted?)")
-                return
-            }
-
-            // inherit the claimed ed25519 key from the setup message
-            keysClaimed = event.getKeysClaimed().toMutableMap()
-        }
-
-        Timber.tag(loggerTag.value).i("onRoomKeyEvent addInboundGroupSession ${roomKeyContent.sessionId}")
-        val addSessionResult = olmDevice.addInboundGroupSession(
-                roomKeyContent.sessionId,
-                roomKeyContent.sessionKey,
-                roomKeyContent.roomId,
-                senderKey,
-                forwardingCurve25519KeyChain,
-                keysClaimed,
-                exportFormat
-        )
-
-        when (addSessionResult) {
-            is MXOlmDevice.AddSessionResult.Imported               -> addSessionResult.ratchetIndex
-            is MXOlmDevice.AddSessionResult.NotImportedHigherIndex -> addSessionResult.newIndex
-            else                                                   -> null
-        }?.let { index ->
-            if (event.getClearType() == EventType.FORWARDED_ROOM_KEY) {
-                val fromDevice = (event.content?.get("sender_key") as? String)?.let { senderDeviceIdentityKey ->
-                    cryptoStore.getUserDeviceList(event.senderId ?: "")
-                            ?.firstOrNull {
-                                it.identityKey() == senderDeviceIdentityKey
-                            }
-                }?.deviceId
-
-                outgoingKeyRequestManager.onRoomKeyForwarded(
-                        sessionId = roomKeyContent.sessionId,
-                        algorithm = roomKeyContent.algorithm ?: "",
-                        roomId = roomKeyContent.roomId,
-                        senderKey = senderKey,
-                        fromIndex = index,
-                        fromDevice = fromDevice,
-                        event = event)
-
-                cryptoStore.saveIncomingForwardKeyAuditTrail(
-                        roomId = roomKeyContent.roomId,
-                        sessionId = roomKeyContent.sessionId,
-                        senderKey = senderKey,
-                        algorithm = roomKeyContent.algorithm ?: "",
-                        userId = event.senderId ?: "",
-                        deviceId = fromDevice ?: "",
-                        chainIndex = index.toLong())
-
-                // The index is used to decide if we cancel sent request or if we wait for a better key
-                outgoingKeyRequestManager.postCancelRequestForSessionIfNeeded(roomKeyContent.sessionId, roomKeyContent.roomId, senderKey, index)
-            }
-        }
-
-        if (addSessionResult is MXOlmDevice.AddSessionResult.Imported) {
-            Timber.tag(loggerTag.value)
-                    .d("onRoomKeyEvent(${event.getClearType()}) : Added megolm session ${roomKeyContent.sessionId} in ${roomKeyContent.roomId}")
-            defaultKeysBackupService.maybeBackupKeys()
-
-            onNewSession(roomKeyContent.roomId, senderKey, roomKeyContent.sessionId)
-        }
-    }
-
-    /**
-     * Check if the some messages can be decrypted with a new session
-     *
-     * @param roomId the room id where the new Megolm session has been created for, may be null when importing from external sessions
-     * @param senderKey the session sender key
-     * @param sessionId the session id
-     */
-    fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
-        Timber.tag(loggerTag.value).v("ON NEW SESSION $sessionId - $senderKey")
-        newSessionListener?.onNewSession(roomId, senderKey, sessionId)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
deleted file mode 100644
index 096773a959..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.megolm
-
-import dagger.Lazy
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.session.StreamEventsManager
-import javax.inject.Inject
-
-internal class MXMegolmDecryptionFactory @Inject constructor(
-        private val olmDevice: MXOlmDevice,
-        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
-        private val cryptoStore: IMXCryptoStore,
-        private val eventsManager: Lazy<StreamEventsManager>
-) {
-
-    fun create(): MXMegolmDecryption {
-        return MXMegolmDecryption(
-                olmDevice,
-                outgoingKeyRequestManager,
-                cryptoStore,
-                eventsManager)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
deleted file mode 100644
index 0131f54ce9..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.megolm
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.withLock
-import kotlinx.coroutines.withContext
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.api.session.crypto.model.forEach
-import org.matrix.android.sdk.api.session.events.model.Content
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldContent
-import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
-import org.matrix.android.sdk.internal.crypto.model.toDebugCount
-import org.matrix.android.sdk.internal.crypto.model.toDebugString
-import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.util.JsonCanonicalizer
-import org.matrix.android.sdk.internal.util.convertToUTF8
-import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
-
-private val loggerTag = LoggerTag("MXMegolmEncryption", LoggerTag.CRYPTO)
-
-internal class MXMegolmEncryption(
-        // The id of the room we will be sending to.
-        private val roomId: String,
-        private val olmDevice: MXOlmDevice,
-        private val defaultKeysBackupService: DefaultKeysBackupService,
-        private val cryptoStore: IMXCryptoStore,
-        private val deviceListManager: DeviceListManager,
-        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
-        private val myUserId: String,
-        private val myDeviceId: String,
-        private val sendToDeviceTask: SendToDeviceTask,
-        private val messageEncrypter: MessageEncrypter,
-        private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoCoroutineScope: CoroutineScope,
-        private val clock: Clock,
-) : IMXEncrypting, IMXGroupEncryption {
-
-    // OutboundSessionInfo. Null if we haven't yet started setting one up. Note
-    // that even if this is non-null, it may not be ready for use (in which
-    // case outboundSession.shareOperation will be non-null.)
-    private var outboundSession: MXOutboundSessionInfo? = null
-
-    init {
-        // restore existing outbound session if any
-        outboundSession = olmDevice.restoreOutboundGroupSessionForRoom(roomId)
-    }
-
-    // Default rotation periods
-    // TODO: Make it configurable via parameters
-    // Session rotation periods
-    private var sessionRotationPeriodMsgs: Int = 100
-    private var sessionRotationPeriodMs: Int = 7 * 24 * 3600 * 1000
-
-    override suspend fun encryptEventContent(eventContent: Content,
-                                             eventType: String,
-                                             userIds: List<String>): Content {
-        val ts = clock.epochMillis()
-        Timber.tag(loggerTag.value).v("encryptEventContent : getDevicesInRoom")
-        val devices = getDevicesInRoom(userIds)
-        Timber.tag(loggerTag.value).d("encrypt event in room=$roomId - devices count in room ${devices.allowedDevices.toDebugCount()}")
-        Timber.tag(loggerTag.value).v("encryptEventContent ${clock.epochMillis() - ts}: getDevicesInRoom ${devices.allowedDevices.toDebugString()}")
-        val outboundSession = ensureOutboundSession(devices.allowedDevices)
-
-        return encryptContent(outboundSession, eventType, eventContent)
-                .also {
-                    notifyWithheldForSession(devices.withHeldDevices, outboundSession)
-                    // annoyingly we have to serialize again the saved outbound session to store message index :/
-                    // if not we would see duplicate message index errors
-                    olmDevice.storeOutboundGroupSessionForRoom(roomId, outboundSession.sessionId)
-                    Timber.tag(loggerTag.value).d("encrypt event in room=$roomId Finished in ${clock.epochMillis() - ts} millis")
-                }
-    }
-
-    private fun notifyWithheldForSession(devices: MXUsersDevicesMap<WithHeldCode>, outboundSession: MXOutboundSessionInfo) {
-        // offload to computation thread
-        cryptoCoroutineScope.launch(coroutineDispatchers.computation) {
-            mutableListOf<Pair<UserDevice, WithHeldCode>>().apply {
-                devices.forEach { userId, deviceId, withheldCode ->
-                    this.add(UserDevice(userId, deviceId) to withheldCode)
-                }
-            }.groupBy(
-                    { it.second },
-                    { it.first }
-            ).forEach { (code, targets) ->
-                notifyKeyWithHeld(targets, outboundSession.sessionId, olmDevice.deviceCurve25519Key, code)
-            }
-        }
-    }
-
-    override fun discardSessionKey() {
-        outboundSession = null
-        olmDevice.discardOutboundGroupSessionForRoom(roomId)
-    }
-
-    override suspend fun preshareKey(userIds: List<String>) {
-        val ts = clock.epochMillis()
-        Timber.tag(loggerTag.value).d("preshareKey started in $roomId ...")
-        val devices = getDevicesInRoom(userIds)
-        val outboundSession = ensureOutboundSession(devices.allowedDevices)
-
-        notifyWithheldForSession(devices.withHeldDevices, outboundSession)
-
-        Timber.tag(loggerTag.value).d("preshareKey in $roomId done in  ${clock.epochMillis() - ts} millis")
-    }
-
-    /**
-     * Prepare a new session.
-     *
-     * @return the session description
-     */
-    private fun prepareNewSessionInRoom(): MXOutboundSessionInfo {
-        Timber.tag(loggerTag.value).v("prepareNewSessionInRoom() ")
-        val sessionId = olmDevice.createOutboundGroupSessionForRoom(roomId)
-
-        val keysClaimedMap = mapOf(
-                "ed25519" to olmDevice.deviceEd25519Key!!
-        )
-
-        olmDevice.addInboundGroupSession(
-                sessionId!!, olmDevice.getSessionKey(sessionId)!!, roomId, olmDevice.deviceCurve25519Key!!,
-                emptyList(), keysClaimedMap, false
-        )
-
-        defaultKeysBackupService.maybeBackupKeys()
-
-        return MXOutboundSessionInfo(sessionId, SharedWithHelper(roomId, sessionId, cryptoStore), clock)
-    }
-
-    /**
-     * Ensure the outbound session
-     *
-     * @param devicesInRoom the devices list
-     */
-    private suspend fun ensureOutboundSession(devicesInRoom: MXUsersDevicesMap<CryptoDeviceInfo>): MXOutboundSessionInfo {
-        Timber.tag(loggerTag.value).v("ensureOutboundSession roomId:$roomId")
-        var session = outboundSession
-        if (session == null ||
-                // Need to make a brand new session?
-                session.needsRotation(sessionRotationPeriodMsgs, sessionRotationPeriodMs) ||
-                // Determine if we have shared with anyone we shouldn't have
-                session.sharedWithTooManyDevices(devicesInRoom)) {
-            Timber.tag(loggerTag.value).d("roomId:$roomId Starting new megolm session because we need to rotate.")
-            session = prepareNewSessionInRoom()
-            outboundSession = session
-        }
-        val safeSession = session
-        val shareMap = HashMap<String, MutableList<CryptoDeviceInfo>>()/* userId */
-        val userIds = devicesInRoom.userIds
-        for (userId in userIds) {
-            val deviceIds = devicesInRoom.getUserDeviceIds(userId)
-            for (deviceId in deviceIds!!) {
-                val deviceInfo = devicesInRoom.getObject(userId, deviceId)
-                if (deviceInfo != null && !cryptoStore.getSharedSessionInfo(roomId, safeSession.sessionId, deviceInfo).found) {
-                    val devices = shareMap.getOrPut(userId) { ArrayList() }
-                    devices.add(deviceInfo)
-                }
-            }
-        }
-        val devicesCount = shareMap.entries.fold(0) { acc, new -> acc + new.value.size }
-        Timber.tag(loggerTag.value).d("roomId:$roomId found $devicesCount devices without megolm session(${session.sessionId})")
-        shareKey(safeSession, shareMap)
-        return safeSession
-    }
-
-    /**
-     * Share the device key to a list of users
-     *
-     * @param session        the session info
-     * @param devicesByUsers the devices map
-     */
-    private suspend fun shareKey(session: MXOutboundSessionInfo,
-                                 devicesByUsers: Map<String, List<CryptoDeviceInfo>>) {
-        // nothing to send, the task is done
-        if (devicesByUsers.isEmpty()) {
-            Timber.tag(loggerTag.value).v("shareKey() : nothing more to do")
-            return
-        }
-        // reduce the map size to avoid request timeout when there are too many devices (Users size  * devices per user)
-        val subMap = HashMap<String, List<CryptoDeviceInfo>>()
-        var devicesCount = 0
-        for ((userId, devices) in devicesByUsers) {
-            subMap[userId] = devices
-            devicesCount += devices.size
-            if (devicesCount > 100) {
-                break
-            }
-        }
-        Timber.tag(loggerTag.value).v("shareKey() ; sessionId<${session.sessionId}> userId ${subMap.keys}")
-        shareUserDevicesKey(session, subMap)
-        val remainingDevices = devicesByUsers - subMap.keys
-        shareKey(session, remainingDevices)
-    }
-
-    /**
-     * Share the device keys of a an user
-     *
-     * @param session       the session info
-     * @param devicesByUser the devices map
-     */
-    private suspend fun shareUserDevicesKey(session: MXOutboundSessionInfo,
-                                            devicesByUser: Map<String, List<CryptoDeviceInfo>>) {
-        val sessionKey = olmDevice.getSessionKey(session.sessionId)
-        val chainIndex = olmDevice.getMessageIndex(session.sessionId)
-
-        val submap = HashMap<String, Any>()
-        submap["algorithm"] = MXCRYPTO_ALGORITHM_MEGOLM
-        submap["room_id"] = roomId
-        submap["session_id"] = session.sessionId
-        submap["session_key"] = sessionKey!!
-        submap["chain_index"] = chainIndex
-
-        val payload = HashMap<String, Any>()
-        payload["type"] = EventType.ROOM_KEY
-        payload["content"] = submap
-
-        var t0 = clock.epochMillis()
-        Timber.tag(loggerTag.value).v("shareUserDevicesKey() : starts")
-
-        val results = ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-        Timber.tag(loggerTag.value).v(
-                """shareUserDevicesKey(): ensureOlmSessionsForDevices succeeds after ${clock.epochMillis() - t0} ms"""
-                        .trimMargin()
-        )
-        val contentMap = MXUsersDevicesMap<Any>()
-        var haveTargets = false
-        val userIds = results.userIds
-        val noOlmToNotify = mutableListOf<UserDevice>()
-        for (userId in userIds) {
-            val devicesToShareWith = devicesByUser[userId]
-            for ((deviceID) in devicesToShareWith!!) {
-                val sessionResult = results.getObject(userId, deviceID)
-                if (sessionResult?.sessionId == null) {
-                    // no session with this device, probably because there
-                    // were no one-time keys.
-
-                    // MSC 2399
-                    // send withheld m.no_olm: an olm session could not be established.
-                    // This may happen, for example, if the sender was unable to obtain a one-time key from the recipient.
-                    Timber.tag(loggerTag.value).v("shareUserDevicesKey() : No Olm Session for $userId:$deviceID mark for withheld")
-                    noOlmToNotify.add(UserDevice(userId, deviceID))
-                    continue
-                }
-                Timber.tag(loggerTag.value).v("shareUserDevicesKey() : Add to share keys contentMap for $userId:$deviceID")
-                contentMap.setObject(userId, deviceID, messageEncrypter.encryptMessage(payload, listOf(sessionResult.deviceInfo)))
-                haveTargets = true
-            }
-        }
-
-        // Add the devices we have shared with to session.sharedWithDevices.
-        // we deliberately iterate over devicesByUser (ie, the devices we
-        // attempted to share with) rather than the contentMap (those we did
-        // share with), because we don't want to try to claim a one-time-key
-        // for dead devices on every message.
-        for ((_, devicesToShareWith) in devicesByUser) {
-            for (deviceInfo in devicesToShareWith) {
-                session.sharedWithHelper.markedSessionAsShared(deviceInfo, chainIndex)
-                // XXX is it needed to add it to the audit trail?
-                // For now decided that no, we are more interested by forward trail
-            }
-        }
-
-        if (haveTargets) {
-            t0 = clock.epochMillis()
-            Timber.tag(loggerTag.value).i("shareUserDevicesKey() ${session.sessionId} : has target")
-            Timber.tag(loggerTag.value).d("sending to device room key for ${session.sessionId} to ${contentMap.toDebugString()}")
-            val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, contentMap)
-            try {
-                withContext(coroutineDispatchers.io) {
-                    sendToDeviceTask.execute(sendToDeviceParams)
-                }
-                Timber.tag(loggerTag.value).i("shareUserDevicesKey() : sendToDevice succeeds after ${clock.epochMillis() - t0} ms")
-            } catch (failure: Throwable) {
-                // What to do here...
-                Timber.tag(loggerTag.value).e("shareUserDevicesKey() : Failed to share <${session.sessionId}>")
-            }
-        } else {
-            Timber.tag(loggerTag.value).i("shareUserDevicesKey() : no need to share key")
-        }
-
-        if (noOlmToNotify.isNotEmpty()) {
-            // XXX offload?, as they won't read the message anyhow?
-            notifyKeyWithHeld(
-                    noOlmToNotify,
-                    session.sessionId,
-                    olmDevice.deviceCurve25519Key,
-                    WithHeldCode.NO_OLM
-            )
-        }
-    }
-
-    private suspend fun notifyKeyWithHeld(targets: List<UserDevice>,
-                                          sessionId: String,
-                                          senderKey: String?,
-                                          code: WithHeldCode) {
-        Timber.tag(loggerTag.value).d(
-                "notifyKeyWithHeld() :sending withheld for session:$sessionId and code $code to" +
-                        " ${targets.joinToString { "${it.userId}|${it.deviceId}" }}"
-        )
-        val withHeldContent = RoomKeyWithHeldContent(
-                roomId = roomId,
-                senderKey = senderKey,
-                algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
-                sessionId = sessionId,
-                codeString = code.value,
-                fromDevice = myDeviceId
-        )
-        val params = SendToDeviceTask.Params(
-                EventType.ROOM_KEY_WITHHELD,
-                MXUsersDevicesMap<Any>().apply {
-                    targets.forEach {
-                        setObject(it.userId, it.deviceId, withHeldContent)
-                    }
-                }
-        )
-        try {
-            withContext(coroutineDispatchers.io) {
-                sendToDeviceTask.execute(params)
-            }
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value)
-                    .e("notifyKeyWithHeld() :$sessionId Failed to send withheld  ${targets.map { "${it.userId}|${it.deviceId}" }}")
-        }
-    }
-
-    /**
-     * process the pending encryptions
-     */
-    private fun encryptContent(session: MXOutboundSessionInfo, eventType: String, eventContent: Content): Content {
-        // Everything is in place, encrypt all pending events
-        val payloadJson = HashMap<String, Any>()
-        payloadJson["room_id"] = roomId
-        payloadJson["type"] = eventType
-        payloadJson["content"] = eventContent
-
-        // Get canonical Json from
-
-        val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
-        val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString)
-
-        val map = HashMap<String, Any>()
-        map["algorithm"] = MXCRYPTO_ALGORITHM_MEGOLM
-        map["sender_key"] = olmDevice.deviceCurve25519Key!!
-        map["ciphertext"] = ciphertext!!
-        map["session_id"] = session.sessionId
-
-        // Include our device ID so that recipients can send us a
-        // m.new_device message if they don't have our session key.
-        map["device_id"] = myDeviceId
-        session.useCount++
-        return map
-    }
-
-    /**
-     * Get the list of devices which can encrypt data to.
-     * This method must be called in getDecryptingThreadHandler() thread.
-     *
-     * @param userIds  the user ids whose devices must be checked.
-     */
-    private suspend fun getDevicesInRoom(userIds: List<String>): DeviceInRoomInfo {
-        // We are happy to use a cached version here: we assume that if we already
-        // have a list of the user's devices, then we already share an e2e room
-        // with them, which means that they will have announced any new devices via
-        // an m.new_device.
-        val keys = deviceListManager.downloadKeys(userIds, false)
-        val encryptToVerifiedDevicesOnly = cryptoStore.getGlobalBlacklistUnverifiedDevices() ||
-                cryptoStore.getRoomsListBlacklistUnverifiedDevices().contains(roomId)
-
-        val devicesInRoom = DeviceInRoomInfo()
-        val unknownDevices = MXUsersDevicesMap<CryptoDeviceInfo>()
-
-        for (userId in keys.userIds) {
-            val deviceIds = keys.getUserDeviceIds(userId) ?: continue
-            for (deviceId in deviceIds) {
-                val deviceInfo = keys.getObject(userId, deviceId) ?: continue
-                if (warnOnUnknownDevicesRepository.warnOnUnknownDevices() && deviceInfo.isUnknown) {
-                    // The device is not yet known by the user
-                    unknownDevices.setObject(userId, deviceId, deviceInfo)
-                    continue
-                }
-                if (deviceInfo.isBlocked) {
-                    // Remove any blocked devices
-                    devicesInRoom.withHeldDevices.setObject(userId, deviceId, WithHeldCode.BLACKLISTED)
-                    continue
-                }
-
-                if (!deviceInfo.isVerified && encryptToVerifiedDevicesOnly) {
-                    devicesInRoom.withHeldDevices.setObject(userId, deviceId, WithHeldCode.UNVERIFIED)
-                    continue
-                }
-
-                if (deviceInfo.identityKey() == olmDevice.deviceCurve25519Key) {
-                    // Don't bother sending to ourself
-                    continue
-                }
-                devicesInRoom.allowedDevices.setObject(userId, deviceId, deviceInfo)
-            }
-        }
-        if (unknownDevices.isEmpty) {
-            return devicesInRoom
-        } else {
-            throw MXCryptoError.UnknownDevice(unknownDevices)
-        }
-    }
-
-    override suspend fun reshareKey(groupSessionId: String,
-                                    userId: String,
-                                    deviceId: String,
-                                    senderKey: String): Boolean {
-        Timber.tag(loggerTag.value).i("process reshareKey for $groupSessionId to $userId:$deviceId")
-        val deviceInfo = cryptoStore.getUserDevice(userId, deviceId) ?: return false
-                .also { Timber.tag(loggerTag.value).w("reshareKey: Device not found") }
-
-        // Get the chain index of the key we previously sent this device
-        val wasSessionSharedWithUser = cryptoStore.getSharedSessionInfo(roomId, groupSessionId, deviceInfo)
-        if (!wasSessionSharedWithUser.found) {
-            // This session was never shared with this user
-            // Send a room key with held
-            notifyKeyWithHeld(listOf(UserDevice(userId, deviceId)), groupSessionId, senderKey, WithHeldCode.UNAUTHORISED)
-            Timber.tag(loggerTag.value).w("reshareKey: ERROR : Never shared megolm with this device")
-            return false
-        }
-        // if found chain index should not be null
-        val chainIndex = wasSessionSharedWithUser.chainIndex ?: return false
-                .also {
-                    Timber.tag(loggerTag.value).w("reshareKey: Null chain index")
-                }
-
-        val devicesByUser = mapOf(userId to listOf(deviceInfo))
-        val usersDeviceMap = try {
-            ensureOlmSessionsForDevicesAction.handle(devicesByUser)
-        } catch (failure: Throwable) {
-            null
-        }
-        val olmSessionResult = usersDeviceMap?.getObject(userId, deviceId)
-        if (olmSessionResult?.sessionId == null) {
-            Timber.tag(loggerTag.value).w("reshareKey: no session with this device, probably because there were no one-time keys")
-            return false
-        }
-        Timber.tag(loggerTag.value).i(" reshareKey: $groupSessionId:$chainIndex with device $userId:$deviceId using session ${olmSessionResult.sessionId}")
-
-        val sessionHolder = try {
-            olmDevice.getInboundGroupSession(groupSessionId, senderKey, roomId)
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value).e(failure, "shareKeysWithDevice: failed to get session $groupSessionId")
-            return false
-        }
-
-        val export = sessionHolder.mutex.withLock {
-            sessionHolder.wrapper.exportKeys()
-        } ?: return false.also {
-            Timber.tag(loggerTag.value).e("shareKeysWithDevice: failed to export group session $groupSessionId")
-        }
-
-        val payloadJson = mapOf(
-                "type" to EventType.FORWARDED_ROOM_KEY,
-                "content" to export
-        )
-
-        val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo))
-        val sendToDeviceMap = MXUsersDevicesMap<Any>()
-        sendToDeviceMap.setObject(userId, deviceId, encodedPayload)
-        Timber.tag(loggerTag.value).i("reshareKey() : sending session $groupSessionId to $userId:$deviceId")
-        val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap)
-        return try {
-            sendToDeviceTask.execute(sendToDeviceParams)
-            Timber.tag(loggerTag.value).i("reshareKey() : successfully send <$groupSessionId> to $userId:$deviceId")
-            true
-        } catch (failure: Throwable) {
-            Timber.tag(loggerTag.value).e(failure, "reshareKey() : fail to send <$groupSessionId> to $userId:$deviceId")
-            false
-        }
-    }
-
-    data class DeviceInRoomInfo(
-            val allowedDevices: MXUsersDevicesMap<CryptoDeviceInfo> = MXUsersDevicesMap(),
-            val withHeldDevices: MXUsersDevicesMap<WithHeldCode> = MXUsersDevicesMap()
-    )
-
-    data class UserDevice(
-            val userId: String,
-            val deviceId: String
-    )
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt
deleted file mode 100644
index 5c22e5f40c..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.megolm
-
-import kotlinx.coroutines.CoroutineScope
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
-import org.matrix.android.sdk.internal.di.DeviceId
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.util.time.Clock
-import javax.inject.Inject
-
-internal class MXMegolmEncryptionFactory @Inject constructor(
-        private val olmDevice: MXOlmDevice,
-//        private val defaultKeysBackupService: DefaultKeysBackupService,
-        private val cryptoStore: IMXCryptoStore,
-        private val deviceListManager: DeviceListManager,
-        private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
-        @UserId private val userId: String,
-        @DeviceId private val deviceId: String?,
-        private val sendToDeviceTask: SendToDeviceTask,
-        private val messageEncrypter: MessageEncrypter,
-        private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoCoroutineScope: CoroutineScope,
-        private val clock: Clock,
-) {
-
-    fun create(roomId: String): MXMegolmEncryption {
-        return MXMegolmEncryption(
-                roomId = roomId,
-                olmDevice = olmDevice,
-//                defaultKeysBackupService = defaultKeysBackupService,
-                cryptoStore = cryptoStore,
-                deviceListManager = deviceListManager,
-                ensureOlmSessionsForDevicesAction = ensureOlmSessionsForDevicesAction,
-                myUserId = userId,
-                myDeviceId = deviceId!!,
-                sendToDeviceTask = sendToDeviceTask,
-                messageEncrypter = messageEncrypter,
-                warnOnUnknownDevicesRepository = warnOnUnknownDevicesRepository,
-                coroutineDispatchers = coroutineDispatchers,
-                cryptoCoroutineScope = cryptoCoroutineScope,
-                clock = clock,
-        )
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt
deleted file mode 100644
index 28d925d8fd..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXOutboundSessionInfo.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.megolm
-
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.internal.util.time.Clock
-import timber.log.Timber
-
-internal class MXOutboundSessionInfo(
-        // The id of the session
-        val sessionId: String,
-        val sharedWithHelper: SharedWithHelper,
-        private val clock: Clock,
-        // When the session was created
-        private val creationTime: Long = clock.epochMillis(),
-) {
-
-    // Number of times this session has been used
-    var useCount: Int = 0
-
-    fun needsRotation(rotationPeriodMsgs: Int, rotationPeriodMs: Int): Boolean {
-        var needsRotation = false
-        val sessionLifetime = clock.epochMillis() - creationTime
-
-        if (useCount >= rotationPeriodMsgs || sessionLifetime >= rotationPeriodMs) {
-            Timber.v("## needsRotation() : Rotating megolm session after $useCount, ${sessionLifetime}ms")
-            needsRotation = true
-        }
-
-        return needsRotation
-    }
-
-    /**
-     * Determine if this session has been shared with devices which it shouldn't have been.
-     *
-     * @param devicesInRoom the devices map
-     * @return true if we have shared the session with devices which aren't in devicesInRoom.
-     */
-    fun sharedWithTooManyDevices(devicesInRoom: MXUsersDevicesMap<CryptoDeviceInfo>): Boolean {
-        val sharedWithDevices = sharedWithHelper.sharedWithDevices()
-        val userIds = sharedWithDevices.userIds
-
-        for (userId in userIds) {
-            if (null == devicesInRoom.getUserDeviceIds(userId)) {
-                Timber.v("## sharedWithTooManyDevices() : Starting new session because we shared with $userId")
-                return true
-            }
-
-            val deviceIds = sharedWithDevices.getUserDeviceIds(userId)
-
-            for (deviceId in deviceIds!!) {
-                if (null == devicesInRoom.getObject(userId, deviceId)) {
-                    Timber.v("## sharedWithTooManyDevices() : Starting new session because we shared with $userId:$deviceId")
-                    return true
-                }
-            }
-        }
-
-        return false
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt
deleted file mode 100644
index 61ad345c62..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/SharedWithHelper.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.megolm
-
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-
-internal class SharedWithHelper(
-        private val roomId: String,
-        private val sessionId: String,
-        private val cryptoStore: IMXCryptoStore) {
-
-    fun sharedWithDevices(): MXUsersDevicesMap<Int> {
-        return cryptoStore.getSharedWithInfo(roomId, sessionId)
-    }
-
-    fun markedSessionAsShared(deviceInfo: CryptoDeviceInfo, chainIndex: Int) {
-        cryptoStore.markedSessionAsShared(
-                roomId = roomId,
-                sessionId = sessionId,
-                userId = deviceInfo.userId,
-                deviceId = deviceInfo.deviceId,
-                deviceIdentityKey = deviceInfo.identityKey() ?: "",
-                chainIndex = chainIndex
-        )
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
deleted file mode 100644
index 1e66fe84c9..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.olm
-
-import kotlinx.coroutines.sync.withLock
-import org.matrix.android.sdk.api.logger.LoggerTag
-import org.matrix.android.sdk.api.session.crypto.MXCryptoError
-import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
-import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.api.session.events.model.content.OlmEventContent
-import org.matrix.android.sdk.api.session.events.model.content.OlmPayloadContent
-import org.matrix.android.sdk.api.session.events.model.toModel
-import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE
-import org.matrix.android.sdk.api.util.JsonDict
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXDecrypting
-import org.matrix.android.sdk.internal.di.MoshiProvider
-import org.matrix.android.sdk.internal.util.convertFromUTF8
-import timber.log.Timber
-
-private val loggerTag = LoggerTag("MXOlmDecryption", LoggerTag.CRYPTO)
-
-internal class MXOlmDecryption(
-        // The olm device interface
-        private val olmDevice: MXOlmDevice,
-        // the matrix userId
-        private val userId: String) :
-        IMXDecrypting {
-
-    @Throws(MXCryptoError::class)
-    override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
-        val olmEventContent = event.content.toModel<OlmEventContent>() ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : bad event format")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.BAD_EVENT_FORMAT,
-                    MXCryptoError.BAD_EVENT_FORMAT_TEXT_REASON
-            )
-        }
-
-        val cipherText = olmEventContent.ciphertext ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : missing cipher text")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.MISSING_CIPHER_TEXT,
-                    MXCryptoError.MISSING_CIPHER_TEXT_REASON
-            )
-        }
-
-        val senderKey = olmEventContent.senderKey ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : missing sender key")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.MISSING_SENDER_KEY,
-                    MXCryptoError.MISSING_SENDER_KEY_TEXT_REASON
-            )
-        }
-
-        val messageAny = cipherText[olmDevice.deviceCurve25519Key] ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : our device ${olmDevice.deviceCurve25519Key} is not included in recipients")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.NOT_INCLUDE_IN_RECIPIENTS, MXCryptoError.NOT_INCLUDED_IN_RECIPIENT_REASON)
-        }
-
-        // The message for myUser
-        @Suppress("UNCHECKED_CAST")
-        val message = messageAny as JsonDict
-
-        val decryptedPayload = decryptMessage(message, senderKey)
-
-        if (decryptedPayload == null) {
-            Timber.tag(loggerTag.value).e("## decryptEvent() Failed to decrypt Olm event (id= ${event.eventId} from $senderKey")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ENCRYPTED_MESSAGE, MXCryptoError.BAD_ENCRYPTED_MESSAGE_REASON)
-        }
-        val payloadString = convertFromUTF8(decryptedPayload)
-
-        val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
-        val payload = adapter.fromJson(payloadString)
-
-        if (payload == null) {
-            Timber.tag(loggerTag.value).e("## decryptEvent failed : null payload")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.UNABLE_TO_DECRYPT, MXCryptoError.MISSING_CIPHER_TEXT_REASON)
-        }
-
-        val olmPayloadContent = OlmPayloadContent.fromJsonString(payloadString) ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : bad olmPayloadContent format")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON)
-        }
-
-        if (olmPayloadContent.recipient.isNullOrBlank()) {
-            val reason = String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient")
-            Timber.tag(loggerTag.value).e("## decryptEvent() : $reason")
-            throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY, reason)
-        }
-
-        if (olmPayloadContent.recipient != userId) {
-            Timber.tag(loggerTag.value).e(
-                    "## decryptEvent() : Event ${event.eventId}:" +
-                            " Intended recipient ${olmPayloadContent.recipient} does not match our id $userId"
-            )
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.BAD_RECIPIENT,
-                    String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient)
-            )
-        }
-
-        val recipientKeys = olmPayloadContent.recipientKeys ?: run {
-            Timber.tag(loggerTag.value).e(
-                    "## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" +
-                            " property; cannot prevent unknown-key attack"
-            )
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.MISSING_PROPERTY,
-                    String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "recipient_keys")
-            )
-        }
-
-        val ed25519 = recipientKeys["ed25519"]
-
-        if (ed25519 != olmDevice.deviceEd25519Key) {
-            Timber.tag(loggerTag.value).e("## decryptEvent() : Event ${event.eventId}: Intended recipient ed25519 key $ed25519 did not match ours")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.BAD_RECIPIENT_KEY,
-                    MXCryptoError.BAD_RECIPIENT_KEY_REASON
-            )
-        }
-
-        if (olmPayloadContent.sender.isNullOrBlank()) {
-            Timber.tag(loggerTag.value)
-                    .e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'sender' property; cannot prevent unknown-key attack")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.MISSING_PROPERTY,
-                    String.format(MXCryptoError.ERROR_MISSING_PROPERTY_REASON, "sender")
-            )
-        }
-
-        if (olmPayloadContent.sender != event.senderId) {
-            Timber.tag(loggerTag.value)
-                    .e("Event ${event.eventId}:  sender ${olmPayloadContent.sender} does not match reported sender ${event.senderId}")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.FORWARDED_MESSAGE,
-                    String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender)
-            )
-        }
-
-        if (olmPayloadContent.roomId != event.roomId) {
-            Timber.tag(loggerTag.value)
-                    .e("## decryptEvent() : Event ${event.eventId}:  room ${olmPayloadContent.roomId} does not match reported room ${event.roomId}")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.BAD_ROOM,
-                    String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.roomId)
-            )
-        }
-
-        val keys = olmPayloadContent.keys ?: run {
-            Timber.tag(loggerTag.value).e("## decryptEvent failed : null keys")
-            throw MXCryptoError.Base(
-                    MXCryptoError.ErrorType.UNABLE_TO_DECRYPT,
-                    MXCryptoError.MISSING_CIPHER_TEXT_REASON
-            )
-        }
-
-        return MXEventDecryptionResult(
-                clearEvent = payload,
-                senderCurve25519Key = senderKey,
-                claimedEd25519Key = keys["ed25519"]
-        )
-    }
-
-    /**
-     * Attempt to decrypt an Olm message.
-     *
-     * @param theirDeviceIdentityKey the Curve25519 identity key of the sender.
-     * @param message                message object, with 'type' and 'body' fields.
-     * @return payload, if decrypted successfully.
-     */
-    private suspend fun decryptMessage(message: JsonDict, theirDeviceIdentityKey: String): String? {
-        val sessionIds = olmDevice.getSessionIds(theirDeviceIdentityKey)
-
-        val messageBody = message["body"] as? String ?: return null
-        val messageType = when (val typeAsVoid = message["type"]) {
-            is Double -> typeAsVoid.toInt()
-            is Int    -> typeAsVoid
-            is Long   -> typeAsVoid.toInt()
-            else      -> return null
-        }
-
-        // Try each session in turn
-        // decryptionErrors = {};
-
-        val isPreKey = messageType == 0
-        // we want to synchronize on prekey if not we could end up create two olm sessions
-        // Not very clear but it looks like the js-sdk for consistency
-        return if (isPreKey) {
-            olmDevice.mutex.withLock {
-                reallyDecryptMessage(sessionIds, messageBody, messageType, theirDeviceIdentityKey)
-            }
-        } else {
-            reallyDecryptMessage(sessionIds, messageBody, messageType, theirDeviceIdentityKey)
-        }
-    }
-
-    private suspend fun reallyDecryptMessage(sessionIds: List<String>, messageBody: String, messageType: Int, theirDeviceIdentityKey: String): String? {
-        Timber.tag(loggerTag.value).d("decryptMessage() try to decrypt olm message type:$messageType from ${sessionIds.size} known sessions")
-        for (sessionId in sessionIds) {
-            val payload = try {
-                olmDevice.decryptMessage(messageBody, messageType, sessionId, theirDeviceIdentityKey)
-            } catch (throwable: Exception) {
-                // As we are trying one by one, we don't really care of the error here
-                Timber.tag(loggerTag.value).d("decryptMessage() failed with session $sessionId")
-                null
-            }
-
-            if (null != payload) {
-                Timber.tag(loggerTag.value).v("## decryptMessage() : Decrypted Olm message from $theirDeviceIdentityKey with session $sessionId")
-                return payload
-            } else {
-                val foundSession = olmDevice.matchesSession(theirDeviceIdentityKey, sessionId, messageType, messageBody)
-
-                if (foundSession) {
-                    // Decryption failed, but it was a prekey message matching this
-                    // session, so it should have worked.
-                    Timber.tag(loggerTag.value).e("## decryptMessage() : Error decrypting prekey message with existing session id $sessionId:TODO")
-                    return null
-                }
-            }
-        }
-
-        if (messageType != 0) {
-            // not a prekey message, so it should have matched an existing session, but it
-            // didn't work.
-
-            if (sessionIds.isEmpty()) {
-                Timber.tag(loggerTag.value).e("## decryptMessage() : No existing sessions")
-            } else {
-                Timber.tag(loggerTag.value).e("## decryptMessage() : Error decrypting non-prekey message with existing sessions")
-            }
-
-            return null
-        }
-
-        // prekey message which doesn't match any existing sessions: make a new
-        // session.
-        // XXXX Possible races here? if concurrent access for same prekey message, we might create 2 sessions?
-        Timber.tag(loggerTag.value).d("## decryptMessage() :  Create inbound group session from prekey sender:$theirDeviceIdentityKey")
-
-        val res = olmDevice.createInboundSession(theirDeviceIdentityKey, messageType, messageBody)
-
-        if (null == res) {
-            Timber.tag(loggerTag.value).e("## decryptMessage() :  Error decrypting non-prekey message with existing sessions")
-            return null
-        }
-
-        Timber.tag(loggerTag.value).v("## decryptMessage() :  Created new inbound Olm session get id ${res["session_id"]} with $theirDeviceIdentityKey")
-
-        return res["payload"]
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt
deleted file mode 100644
index c842c54041..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryption.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.olm
-
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.session.events.model.Content
-import org.matrix.android.sdk.api.session.events.model.toContent
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForUsersAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-
-internal class MXOlmEncryption(
-        private val roomId: String,
-        private val olmDevice: MXOlmDevice,
-        private val cryptoStore: IMXCryptoStore,
-        private val messageEncrypter: MessageEncrypter,
-        private val deviceListManager: DeviceListManager,
-        private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) :
-        IMXEncrypting {
-
-    override suspend fun encryptEventContent(eventContent: Content, eventType: String, userIds: List<String>): Content {
-        // pick the list of recipients based on the membership list.
-        //
-        // TODO: there is a race condition here! What if a new user turns up
-        ensureSession(userIds)
-        val deviceInfos = ArrayList<CryptoDeviceInfo>()
-        for (userId in userIds) {
-            val devices = cryptoStore.getUserDevices(userId)?.values.orEmpty()
-            for (device in devices) {
-                val key = device.identityKey()
-                if (key == olmDevice.deviceCurve25519Key) {
-                    // Don't bother setting up session to ourself
-                    continue
-                }
-                if (device.isBlocked) {
-                    // Don't bother setting up sessions with blocked users
-                    continue
-                }
-                deviceInfos.add(device)
-            }
-        }
-
-        val messageMap = mapOf(
-                "room_id" to roomId,
-                "type" to eventType,
-                "content" to eventContent
-        )
-
-        messageEncrypter.encryptMessage(messageMap, deviceInfos)
-        return messageMap.toContent()
-    }
-
-    /**
-     * Ensure that the session
-     *
-     * @param users    the user ids list
-     */
-    private suspend fun ensureSession(users: List<String>) {
-        deviceListManager.downloadKeys(users, false)
-        ensureOlmSessionsForUsersAction.handle(users)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt
deleted file mode 100644
index 44e55900e4..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.algorithms.olm
-
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForUsersAction
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import javax.inject.Inject
-
-internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice,
-                                                          private val cryptoStore: IMXCryptoStore,
-                                                          private val messageEncrypter: MessageEncrypter,
-                                                          private val deviceListManager: DeviceListManager,
-                                                          private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                                          private val ensureOlmSessionsForUsersAction: EnsureOlmSessionsForUsersAction) {
-
-    fun create(roomId: String): MXOlmEncryption {
-        return MXOlmEncryption(
-                roomId,
-                olmDevice,
-                cryptoStore,
-                messageEncrypter,
-                deviceListManager,
-                ensureOlmSessionsForUsersAction
-        )
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt
deleted file mode 100644
index 02ea943284..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.matrix.android.sdk.internal.crypto.crosssigning
-
-import kotlinx.coroutines.withContext
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.extensions.orFalse
-import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
-import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.task.Task
-import javax.inject.Inject
-
-internal interface ComputeTrustTask : Task<ComputeTrustTask.Params, RoomEncryptionTrustLevel> {
-    data class Params(
-            val activeMemberUserIds: List<String>,
-            val isDirectRoom: Boolean
-    )
-}
-
-internal class DefaultComputeTrustTask @Inject constructor(
-        private val cryptoStore: IMXCryptoStore,
-        @UserId private val userId: String,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers
-) : ComputeTrustTask {
-
-    override suspend fun execute(params: ComputeTrustTask.Params): RoomEncryptionTrustLevel = withContext(coroutineDispatchers.crypto) {
-        // The set of “all users” depends on the type of room:
-        // For regular / topic rooms, all users including yourself, are considered when decorating a room
-        // For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
-        val listToCheck = if (params.isDirectRoom) {
-            params.activeMemberUserIds.filter { it != userId }
-        } else {
-            params.activeMemberUserIds
-        }
-
-        val allTrustedUserIds = listToCheck
-                .filter { userId -> getUserCrossSigningKeys(userId)?.isTrusted() == true }
-
-        if (allTrustedUserIds.isEmpty()) {
-            RoomEncryptionTrustLevel.Default
-        } else {
-            // If one of the verified user as an untrusted device -> warning
-            // If all devices of all verified users are trusted -> green
-            // else -> black
-            allTrustedUserIds
-                    .mapNotNull { cryptoStore.getUserDeviceList(it) }
-                    .flatten()
-                    .let { allDevices ->
-                        if (getMyCrossSigningKeys() != null) {
-                            allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() }
-                        } else {
-                            // Legacy method
-                            allDevices.any { !it.isVerified }
-                        }
-                    }
-                    .let { hasWarning ->
-                        if (hasWarning) {
-                            RoomEncryptionTrustLevel.Warning
-                        } else {
-                            if (listToCheck.size == allTrustedUserIds.size) {
-                                // all users are trusted and all devices are verified
-                                RoomEncryptionTrustLevel.Trusted
-                            } else {
-                                RoomEncryptionTrustLevel.Default
-                            }
-                        }
-                    }
-        }
-    }
-
-    private fun getUserCrossSigningKeys(otherUserId: String): MXCrossSigningInfo? {
-        return cryptoStore.getCrossSigningInfo(otherUserId)
-    }
-
-    private fun getMyCrossSigningKeys(): MXCrossSigningInfo? {
-        return cryptoStore.getMyCrossSigningInfo()
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
deleted file mode 100644
index b8cdc922cc..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.crosssigning
-
-import androidx.lifecycle.LiveData
-import androidx.work.BackoffPolicy
-import androidx.work.ExistingWorkPolicy
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import org.matrix.android.sdk.api.MatrixCallback
-import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
-import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
-import org.matrix.android.sdk.api.extensions.orFalse
-import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
-import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
-import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustResult
-import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
-import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
-import org.matrix.android.sdk.api.session.crypto.crosssigning.UserTrustResult
-import org.matrix.android.sdk.api.session.crypto.crosssigning.isCrossSignedVerified
-import org.matrix.android.sdk.api.session.crypto.crosssigning.isLocallyVerified
-import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
-import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
-import org.matrix.android.sdk.api.util.Optional
-import org.matrix.android.sdk.api.util.fromBase64
-import org.matrix.android.sdk.internal.crypto.DeviceListManager
-import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
-import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.tasks.InitializeCrossSigningTask
-import org.matrix.android.sdk.internal.crypto.tasks.UploadSignaturesTask
-import org.matrix.android.sdk.internal.di.SessionId
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.di.WorkManagerProvider
-import org.matrix.android.sdk.internal.session.SessionScope
-import org.matrix.android.sdk.internal.task.TaskExecutor
-import org.matrix.android.sdk.internal.task.TaskThread
-import org.matrix.android.sdk.internal.task.configureWith
-import org.matrix.android.sdk.internal.util.JsonCanonicalizer
-import org.matrix.android.sdk.internal.util.logLimit
-import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
-import org.matrix.olm.OlmPkSigning
-import org.matrix.olm.OlmUtility
-import timber.log.Timber
-import java.util.concurrent.TimeUnit
-import javax.inject.Inject
-
-@SessionScope
-internal class DefaultCrossSigningService @Inject constructor(
-        @UserId private val userId: String,
-        @SessionId private val sessionId: String,
-        private val cryptoStore: IMXCryptoStore,
-        private val deviceListManager: DeviceListManager,
-        private val initializeCrossSigningTask: InitializeCrossSigningTask,
-        private val uploadSignaturesTask: UploadSignaturesTask,
-        private val taskExecutor: TaskExecutor,
-        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-        private val cryptoCoroutineScope: CoroutineScope,
-        private val workManagerProvider: WorkManagerProvider,
-        private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
-        private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
-) : CrossSigningService,
-        DeviceListManager.UserDevicesUpdateListener {
-
-    private var olmUtility: OlmUtility? = null
-
-    private var masterPkSigning: OlmPkSigning? = null
-    private var userPkSigning: OlmPkSigning? = null
-    private var selfSigningPkSigning: OlmPkSigning? = null
-
-    init {
-        try {
-            olmUtility = OlmUtility()
-
-            // Try to get stored keys if they exist
-            cryptoStore.getMyCrossSigningInfo()?.let { mxCrossSigningInfo ->
-                Timber.i("## CrossSigning - Found Existing self signed keys")
-                Timber.i("## CrossSigning - Checking if private keys are known")
-
-                cryptoStore.getCrossSigningPrivateKeys()?.let { privateKeysInfo ->
-                    privateKeysInfo.master
-                            ?.fromBase64()
-                            ?.let { privateKeySeed ->
-                                val pkSigning = OlmPkSigning()
-                                if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                                    masterPkSigning = pkSigning
-                                    Timber.i("## CrossSigning - Loading master key success")
-                                } else {
-                                    Timber.w("## CrossSigning - Public master key does not match the private key")
-                                    pkSigning.releaseSigning()
-                                    // TODO untrust?
-                                }
-                            }
-                    privateKeysInfo.user
-                            ?.fromBase64()
-                            ?.let { privateKeySeed ->
-                                val pkSigning = OlmPkSigning()
-                                if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                                    userPkSigning = pkSigning
-                                    Timber.i("## CrossSigning - Loading User Signing key success")
-                                } else {
-                                    Timber.w("## CrossSigning - Public User key does not match the private key")
-                                    pkSigning.releaseSigning()
-                                    // TODO untrust?
-                                }
-                            }
-                    privateKeysInfo.selfSigned
-                            ?.fromBase64()
-                            ?.let { privateKeySeed ->
-                                val pkSigning = OlmPkSigning()
-                                if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                                    selfSigningPkSigning = pkSigning
-                                    Timber.i("## CrossSigning - Loading Self Signing key success")
-                                } else {
-                                    Timber.w("## CrossSigning - Public Self Signing key does not match the private key")
-                                    pkSigning.releaseSigning()
-                                    // TODO untrust?
-                                }
-                            }
-                }
-
-                // Recover local trust in case private key are there?
-                setUserKeysAsTrusted(userId, checkUserTrust(userId).isVerified())
-            }
-        } catch (e: Throwable) {
-            // Mmm this kind of a big issue
-            Timber.e(e, "Failed to initialize Cross Signing")
-        }
-
-        deviceListManager.addListener(this)
-    }
-
-    fun release() {
-        olmUtility?.releaseUtility()
-        listOf(masterPkSigning, userPkSigning, selfSigningPkSigning).forEach { it?.releaseSigning() }
-        deviceListManager.removeListener(this)
-    }
-
-    protected fun finalize() {
-        release()
-    }
-
-    /**
-     *   - Make 3 key pairs (MSK, USK, SSK)
-     *   - Save the private keys with proper security
-     *   - Sign the keys and upload them
-     *   - Sign the current device with SSK and sign MSK with device key (migration) and upload signatures
-     */
-    override fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?, callback: MatrixCallback<Unit>) {
-        Timber.d("## CrossSigning  initializeCrossSigning")
-
-        val params = InitializeCrossSigningTask.Params(
-                interactiveAuthInterceptor = uiaInterceptor
-        )
-        initializeCrossSigningTask.configureWith(params) {
-            this.callbackThread = TaskThread.CRYPTO
-            this.callback = object : MatrixCallback<InitializeCrossSigningTask.Result> {
-                override fun onFailure(failure: Throwable) {
-                    Timber.e(failure, "Error in initializeCrossSigning()")
-                    callback.onFailure(failure)
-                }
-
-                override fun onSuccess(data: InitializeCrossSigningTask.Result) {
-                    val crossSigningInfo = MXCrossSigningInfo(userId, listOf(data.masterKeyInfo, data.userKeyInfo, data.selfSignedKeyInfo))
-                    cryptoStore.setMyCrossSigningInfo(crossSigningInfo)
-                    setUserKeysAsTrusted(userId, true)
-                    cryptoStore.storePrivateKeysInfo(data.masterKeyPK, data.userKeyPK, data.selfSigningKeyPK)
-                    masterPkSigning = OlmPkSigning().apply { initWithSeed(data.masterKeyPK.fromBase64()) }
-                    userPkSigning = OlmPkSigning().apply { initWithSeed(data.userKeyPK.fromBase64()) }
-                    selfSigningPkSigning = OlmPkSigning().apply { initWithSeed(data.selfSigningKeyPK.fromBase64()) }
-
-                    callback.onSuccess(Unit)
-                }
-            }
-        }.executeBy(taskExecutor)
-    }
-
-    override fun onSecretMSKGossip(mskPrivateKey: String) {
-        Timber.i("## CrossSigning - onSecretSSKGossip")
-        val mxCrossSigningInfo = getMyCrossSigningKeys() ?: return Unit.also {
-            Timber.e("## CrossSigning - onSecretMSKGossip() received secret but public key is not known")
-        }
-
-        mskPrivateKey.fromBase64()
-                .let { privateKeySeed ->
-                    val pkSigning = OlmPkSigning()
-                    try {
-                        if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                            masterPkSigning?.releaseSigning()
-                            masterPkSigning = pkSigning
-                            Timber.i("## CrossSigning - Loading MSK success")
-                            cryptoStore.storeMSKPrivateKey(mskPrivateKey)
-                            return
-                        } else {
-                            Timber.e("## CrossSigning - onSecretMSKGossip() private key do not match public key")
-                            pkSigning.releaseSigning()
-                        }
-                    } catch (failure: Throwable) {
-                        Timber.e("## CrossSigning - onSecretMSKGossip() ${failure.localizedMessage}")
-                        pkSigning.releaseSigning()
-                    }
-                }
-    }
-
-    override fun onSecretSSKGossip(sskPrivateKey: String) {
-        Timber.i("## CrossSigning - onSecretSSKGossip")
-        val mxCrossSigningInfo = getMyCrossSigningKeys() ?: return Unit.also {
-            Timber.e("## CrossSigning - onSecretSSKGossip() received secret but public key is not known")
-        }
-
-        sskPrivateKey.fromBase64()
-                .let { privateKeySeed ->
-                    val pkSigning = OlmPkSigning()
-                    try {
-                        if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                            selfSigningPkSigning?.releaseSigning()
-                            selfSigningPkSigning = pkSigning
-                            Timber.i("## CrossSigning - Loading SSK success")
-                            cryptoStore.storeSSKPrivateKey(sskPrivateKey)
-                            return
-                        } else {
-                            Timber.e("## CrossSigning - onSecretSSKGossip() private key do not match public key")
-                            pkSigning.releaseSigning()
-                        }
-                    } catch (failure: Throwable) {
-                        Timber.e("## CrossSigning - onSecretSSKGossip() ${failure.localizedMessage}")
-                        pkSigning.releaseSigning()
-                    }
-                }
-    }
-
-    override fun onSecretUSKGossip(uskPrivateKey: String) {
-        Timber.i("## CrossSigning - onSecretUSKGossip")
-        val mxCrossSigningInfo = getMyCrossSigningKeys() ?: return Unit.also {
-            Timber.e("## CrossSigning - onSecretUSKGossip() received secret but public key is not knwow ")
-        }
-
-        uskPrivateKey.fromBase64()
-                .let { privateKeySeed ->
-                    val pkSigning = OlmPkSigning()
-                    try {
-                        if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                            userPkSigning?.releaseSigning()
-                            userPkSigning = pkSigning
-                            Timber.i("## CrossSigning - Loading USK success")
-                            cryptoStore.storeUSKPrivateKey(uskPrivateKey)
-                            return
-                        } else {
-                            Timber.e("## CrossSigning - onSecretUSKGossip() private key do not match public key")
-                            pkSigning.releaseSigning()
-                        }
-                    } catch (failure: Throwable) {
-                        pkSigning.releaseSigning()
-                    }
-                }
-    }
-
-    override fun checkTrustFromPrivateKeys(masterKeyPrivateKey: String?,
-                                           uskKeyPrivateKey: String?,
-                                           sskPrivateKey: String?
-    ): UserTrustResult {
-        val mxCrossSigningInfo = getMyCrossSigningKeys() ?: return UserTrustResult.CrossSigningNotConfigured(userId)
-
-        var masterKeyIsTrusted = false
-        var userKeyIsTrusted = false
-        var selfSignedKeyIsTrusted = false
-
-        masterKeyPrivateKey?.fromBase64()
-                ?.let { privateKeySeed ->
-                    val pkSigning = OlmPkSigning()
-                    try {
-                        if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                            masterPkSigning?.releaseSigning()
-                            masterPkSigning = pkSigning
-                            masterKeyIsTrusted = true
-                            Timber.i("## CrossSigning - Loading master key success")
-                        } else {
-                            pkSigning.releaseSigning()
-                        }
-                    } catch (failure: Throwable) {
-                        pkSigning.releaseSigning()
-                    }
-                }
-
-        uskKeyPrivateKey?.fromBase64()
-                ?.let { privateKeySeed ->
-                    val pkSigning = OlmPkSigning()
-                    try {
-                        if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                            userPkSigning?.releaseSigning()
-                            userPkSigning = pkSigning
-                            userKeyIsTrusted = true
-                            Timber.i("## CrossSigning - Loading master key success")
-                        } else {
-                            pkSigning.releaseSigning()
-                        }
-                    } catch (failure: Throwable) {
-                        pkSigning.releaseSigning()
-                    }
-                }
-
-        sskPrivateKey?.fromBase64()
-                ?.let { privateKeySeed ->
-                    val pkSigning = OlmPkSigning()
-                    try {
-                        if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                            selfSigningPkSigning?.releaseSigning()
-                            selfSigningPkSigning = pkSigning
-                            selfSignedKeyIsTrusted = true
-                            Timber.i("## CrossSigning - Loading master key success")
-                        } else {
-                            pkSigning.releaseSigning()
-                        }
-                    } catch (failure: Throwable) {
-                        pkSigning.releaseSigning()
-                    }
-                }
-
-        if (!masterKeyIsTrusted || !userKeyIsTrusted || !selfSignedKeyIsTrusted) {
-            return UserTrustResult.KeysNotTrusted(mxCrossSigningInfo)
-        } else {
-            cryptoStore.markMyMasterKeyAsLocallyTrusted(true)
-            val checkSelfTrust = checkSelfTrust()
-            if (checkSelfTrust.isVerified()) {
-                cryptoStore.storePrivateKeysInfo(masterKeyPrivateKey, uskKeyPrivateKey, sskPrivateKey)
-                setUserKeysAsTrusted(userId, true)
-            }
-            return checkSelfTrust
-        }
-    }
-
-    /**
-     *
-     *  ┏━━━━━━━━┓                             ┏━━━━━━━━┓
-     *  ┃ ALICE  ┃                             ┃  BOB   ┃
-     *  ┗━━━━━━━━┛                             ┗━━━━━━━━┛
-     *   MSK                      ┌────────────▶  MSK
-     *                            │
-     *     │                      │
-     *     │    SSK               │
-     *     │                      │
-     *     │                      │
-     *     └──▶ USK   ────────────┘
-     */
-    override fun isUserTrusted(otherUserId: String): Boolean {
-        return cryptoStore.getCrossSigningInfo(userId)?.isTrusted() == true
-    }
-
-    override fun isCrossSigningVerified(): Boolean {
-        return checkSelfTrust().isVerified()
-    }
-
-    /**
-     * Will not force a download of the key, but will verify signatures trust chain
-     */
-    override fun checkUserTrust(otherUserId: String): UserTrustResult {
-        Timber.v("## CrossSigning  checkUserTrust for $otherUserId")
-        if (otherUserId == userId) {
-            return checkSelfTrust()
-        }
-        // I trust a user if I trust his master key
-        // I can trust the master key if it is signed by my user key
-        // TODO what if the master key is signed by a device key that i have verified
-
-        // First let's get my user key
-        val myCrossSigningInfo = cryptoStore.getCrossSigningInfo(userId)
-
-        checkOtherMSKTrusted(myCrossSigningInfo, cryptoStore.getCrossSigningInfo(otherUserId))
-
-        return UserTrustResult.Success
-    }
-
-    fun checkOtherMSKTrusted(myCrossSigningInfo: MXCrossSigningInfo?, otherInfo: MXCrossSigningInfo?): UserTrustResult {
-        val myUserKey = myCrossSigningInfo?.userKey()
-                ?: return UserTrustResult.CrossSigningNotConfigured(userId)
-
-        if (!myCrossSigningInfo.isTrusted()) {
-            return UserTrustResult.KeysNotTrusted(myCrossSigningInfo)
-        }
-
-        // Let's get the other user  master key
-        val otherMasterKey = otherInfo?.masterKey()
-                ?: return UserTrustResult.UnknownCrossSignatureInfo(otherInfo?.userId ?: "")
-
-        val masterKeySignaturesMadeByMyUserKey = otherMasterKey.signatures
-                ?.get(userId) // Signatures made by me
-                ?.get("ed25519:${myUserKey.unpaddedBase64PublicKey}")
-
-        if (masterKeySignaturesMadeByMyUserKey.isNullOrBlank()) {
-            Timber.d("## CrossSigning  checkUserTrust false for ${otherInfo.userId}, not signed by my UserSigningKey")
-            return UserTrustResult.KeyNotSigned(otherMasterKey)
-        }
-
-        // Check that Alice USK signature of Bob MSK is valid
-        try {
-            olmUtility!!.verifyEd25519Signature(masterKeySignaturesMadeByMyUserKey, myUserKey.unpaddedBase64PublicKey, otherMasterKey.canonicalSignable())
-        } catch (failure: Throwable) {
-            return UserTrustResult.InvalidSignature(myUserKey, masterKeySignaturesMadeByMyUserKey)
-        }
-
-        return UserTrustResult.Success
-    }
-
-    private fun checkSelfTrust(): UserTrustResult {
-        // Special case when it's me,
-        // I have to check that MSK -> USK -> SSK
-        // and that MSK is trusted (i know the private key, or is signed by a trusted device)
-        val myCrossSigningInfo = cryptoStore.getCrossSigningInfo(userId)
-
-        return checkSelfTrust(myCrossSigningInfo, cryptoStore.getUserDeviceList(userId))
-    }
-
-    fun checkSelfTrust(myCrossSigningInfo: MXCrossSigningInfo?, myDevices: List<CryptoDeviceInfo>?): UserTrustResult {
-        // Special case when it's me,
-        // I have to check that MSK -> USK -> SSK
-        // and that MSK is trusted (i know the private key, or is signed by a trusted device)
-//        val myCrossSigningInfo = cryptoStore.getCrossSigningInfo(userId)
-
-        val myMasterKey = myCrossSigningInfo?.masterKey()
-                ?: return UserTrustResult.CrossSigningNotConfigured(userId)
-
-        // Is the master key trusted
-        // 1) check if I know the private key
-        val masterPrivateKey = cryptoStore.getCrossSigningPrivateKeys()
-                ?.master
-                ?.fromBase64()
-
-        var isMaterKeyTrusted = false
-        if (myMasterKey.trustLevel?.locallyVerified == true) {
-            isMaterKeyTrusted = true
-        } else if (masterPrivateKey != null) {
-            // Check if private match public
-            var olmPkSigning: OlmPkSigning? = null
-            try {
-                olmPkSigning = OlmPkSigning()
-                val expectedPK = olmPkSigning.initWithSeed(masterPrivateKey)
-                isMaterKeyTrusted = myMasterKey.unpaddedBase64PublicKey == expectedPK
-            } catch (failure: Throwable) {
-                Timber.e(failure)
-            }
-            olmPkSigning?.releaseSigning()
-        } else {
-            // Maybe it's signed by a locally trusted device?
-            myMasterKey.signatures?.get(userId)?.forEach { (key, value) ->
-                val potentialDeviceId = key.removePrefix("ed25519:")
-                val potentialDevice = myDevices?.firstOrNull { it.deviceId == potentialDeviceId } // cryptoStore.getUserDevice(userId, potentialDeviceId)
-                if (potentialDevice != null && potentialDevice.isVerified) {
-                    // Check signature validity?
-                    try {
-                        olmUtility?.verifyEd25519Signature(value, potentialDevice.fingerprint(), myMasterKey.canonicalSignable())
-                        isMaterKeyTrusted = true
-                        return@forEach
-                    } catch (failure: Throwable) {
-                        // log
-                        Timber.w(failure, "Signature not valid?")
-                    }
-                }
-            }
-        }
-
-        if (!isMaterKeyTrusted) {
-            return UserTrustResult.KeysNotTrusted(myCrossSigningInfo)
-        }
-
-        val myUserKey = myCrossSigningInfo.userKey()
-                ?: return UserTrustResult.CrossSigningNotConfigured(userId)
-
-        val userKeySignaturesMadeByMyMasterKey = myUserKey.signatures
-                ?.get(userId) // Signatures made by me
-                ?.get("ed25519:${myMasterKey.unpaddedBase64PublicKey}")
-
-        if (userKeySignaturesMadeByMyMasterKey.isNullOrBlank()) {
-            Timber.d("## CrossSigning  checkUserTrust false for $userId, USK not signed by MSK")
-            return UserTrustResult.KeyNotSigned(myUserKey)
-        }
-
-        // Check that Alice USK signature of Alice MSK is valid
-        try {
-            olmUtility!!.verifyEd25519Signature(userKeySignaturesMadeByMyMasterKey, myMasterKey.unpaddedBase64PublicKey, myUserKey.canonicalSignable())
-        } catch (failure: Throwable) {
-            return UserTrustResult.InvalidSignature(myUserKey, userKeySignaturesMadeByMyMasterKey)
-        }
-
-        val mySSKey = myCrossSigningInfo.selfSigningKey()
-                ?: return UserTrustResult.CrossSigningNotConfigured(userId)
-
-        val ssKeySignaturesMadeByMyMasterKey = mySSKey.signatures
-                ?.get(userId) // Signatures made by me
-                ?.get("ed25519:${myMasterKey.unpaddedBase64PublicKey}")
-
-        if (ssKeySignaturesMadeByMyMasterKey.isNullOrBlank()) {
-            Timber.d("## CrossSigning  checkUserTrust false for $userId, SSK not signed by MSK")
-            return UserTrustResult.KeyNotSigned(mySSKey)
-        }
-
-        // Check that Alice USK signature of Alice MSK is valid
-        try {
-            olmUtility!!.verifyEd25519Signature(ssKeySignaturesMadeByMyMasterKey, myMasterKey.unpaddedBase64PublicKey, mySSKey.canonicalSignable())
-        } catch (failure: Throwable) {
-            return UserTrustResult.InvalidSignature(mySSKey, ssKeySignaturesMadeByMyMasterKey)
-        }
-
-        return UserTrustResult.Success
-    }
-
-    override fun getUserCrossSigningKeys(otherUserId: String): MXCrossSigningInfo? {
-        return cryptoStore.getCrossSigningInfo(otherUserId)
-    }
-
-    override fun getLiveCrossSigningKeys(userId: String): LiveData<Optional<MXCrossSigningInfo>> {
-        return cryptoStore.getLiveCrossSigningInfo(userId)
-    }
-
-    override fun getMyCrossSigningKeys(): MXCrossSigningInfo? {
-        return cryptoStore.getMyCrossSigningInfo()
-    }
-
-    override fun getCrossSigningPrivateKeys(): PrivateKeysInfo? {
-        return cryptoStore.getCrossSigningPrivateKeys()
-    }
-
-    override fun getLiveCrossSigningPrivateKeys(): LiveData<Optional<PrivateKeysInfo>> {
-        return cryptoStore.getLiveCrossSigningPrivateKeys()
-    }
-
-    override fun canCrossSign(): Boolean {
-        return checkSelfTrust().isVerified() && cryptoStore.getCrossSigningPrivateKeys()?.selfSigned != null &&
-                cryptoStore.getCrossSigningPrivateKeys()?.user != null
-    }
-
-    override fun allPrivateKeysKnown(): Boolean {
-        return checkSelfTrust().isVerified() &&
-                cryptoStore.getCrossSigningPrivateKeys()?.allKnown().orFalse()
-    }
-
-    override fun trustUser(otherUserId: String, callback: MatrixCallback<Unit>) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            Timber.d("## CrossSigning - Mark user $userId as trusted ")
-            // We should have this user keys
-            val otherMasterKeys = getUserCrossSigningKeys(otherUserId)?.masterKey()
-            if (otherMasterKeys == null) {
-                callback.onFailure(Throwable("## CrossSigning - Other master signing key is not known"))
-                return@launch
-            }
-            val myKeys = getUserCrossSigningKeys(userId)
-            if (myKeys == null) {
-                callback.onFailure(Throwable("## CrossSigning - CrossSigning is not setup for this account"))
-                return@launch
-            }
-            val userPubKey = myKeys.userKey()?.unpaddedBase64PublicKey
-            if (userPubKey == null || userPkSigning == null) {
-                callback.onFailure(Throwable("## CrossSigning - Cannot sign from this account, privateKeyUnknown $userPubKey"))
-                return@launch
-            }
-
-            // Sign the other MasterKey with our UserSigning key
-            val newSignature = JsonCanonicalizer.getCanonicalJson(
-                    Map::class.java,
-                    otherMasterKeys.signalableJSONDictionary()
-            ).let { userPkSigning?.sign(it) }
-
-            if (newSignature == null) {
-                // race??
-                callback.onFailure(Throwable("## CrossSigning - Failed to sign"))
-                return@launch
-            }
-
-            cryptoStore.setUserKeysAsTrusted(otherUserId, true)
-            // TODO update local copy with new signature directly here? kind of local echo of trust?
-
-            Timber.d("## CrossSigning - Upload signature of $userId MSK signed by USK")
-            val uploadQuery = UploadSignatureQueryBuilder()
-                    .withSigningKeyInfo(otherMasterKeys.copyForSignature(userId, userPubKey, newSignature))
-                    .build()
-            uploadSignaturesTask.configureWith(UploadSignaturesTask.Params(uploadQuery)) {
-                this.executionThread = TaskThread.CRYPTO
-                this.callback = callback
-            }.executeBy(taskExecutor)
-        }
-    }
-
-    override fun markMyMasterKeyAsTrusted() {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            cryptoStore.markMyMasterKeyAsLocallyTrusted(true)
-            checkSelfTrust()
-            // re-verify all trusts
-            onUsersDeviceUpdate(listOf(userId))
-        }
-    }
-
-    override fun trustDevice(deviceId: String, callback: MatrixCallback<Unit>) {
-        cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
-            // This device should be yours
-            val device = cryptoStore.getUserDevice(userId, deviceId)
-            if (device == null) {
-                callback.onFailure(IllegalArgumentException("This device [$deviceId] is not known, or not yours"))
-                return@launch
-            }
-
-            val myKeys = getUserCrossSigningKeys(userId)
-            if (myKeys == null) {
-                callback.onFailure(Throwable("CrossSigning is not setup for this account"))
-                return@launch
-            }
-
-            val ssPubKey = myKeys.selfSigningKey()?.unpaddedBase64PublicKey
-            if (ssPubKey == null || selfSigningPkSigning == null) {
-                callback.onFailure(Throwable("Cannot sign from this account, public and/or privateKey Unknown $ssPubKey"))
-                return@launch
-            }
-
-            // Sign with self signing
-            val newSignature = selfSigningPkSigning?.sign(device.canonicalSignable())
-
-            if (newSignature == null) {
-                // race??
-                callback.onFailure(Throwable("Failed to sign"))
-                return@launch
-            }
-            val toUpload = device.copy(
-                    signatures = mapOf(
-                            userId
-                                    to
-                                    mapOf(
-                                            "ed25519:$ssPubKey" to newSignature
-                                    )
-                    )
-            )
-
-            val uploadQuery = UploadSignatureQueryBuilder()
-                    .withDeviceInfo(toUpload)
-                    .build()
-            uploadSignaturesTask.configureWith(UploadSignaturesTask.Params(uploadQuery)) {
-                this.executionThread = TaskThread.CRYPTO
-                this.callback = callback
-            }.executeBy(taskExecutor)
-        }
-    }
-
-    override fun checkDeviceTrust(otherUserId: String, otherDeviceId: String, locallyTrusted: Boolean?): DeviceTrustResult {
-        val otherDevice = cryptoStore.getUserDevice(otherUserId, otherDeviceId)
-                ?: return DeviceTrustResult.UnknownDevice(otherDeviceId)
-
-        val myKeys = getUserCrossSigningKeys(userId)
-                ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(userId))
-
-        if (!myKeys.isTrusted()) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(myKeys))
-
-        val otherKeys = getUserCrossSigningKeys(otherUserId)
-                ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(otherUserId))
-
-        // TODO should we force verification ?
-        if (!otherKeys.isTrusted()) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(otherKeys))
-
-        // Check if the trust chain is valid
-        /*
-         *  ┏━━━━━━━━┓                             ┏━━━━━━━━┓
-         *  ┃ ALICE  ┃                             ┃  BOB   ┃
-         *  ┗━━━━━━━━┛                             ┗━━━━━━━━┛
-         *   MSK                      ┌────────────▶MSK
-         *                            │
-         *     │                      │               │
-         *     │    SSK               │               └──▶ SSK  ──────────────────┐
-         *     │                      │                                           │
-         *     │                      │                    USK                    │
-         *     └──▶ USK   ────────────┘              (not visible by              │
-         *                                                Alice)                  │
-         *                                                                        ▼
-         *                                                                ┌──────────────┐
-         *                                                                │ BOB's Device │
-         *                                                                └──────────────┘
-         */
-
-        val otherSSKSignature = otherDevice.signatures?.get(otherUserId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}")
-                ?: return legacyFallbackTrust(
-                        locallyTrusted,
-                        DeviceTrustResult.MissingDeviceSignature(
-                                otherDeviceId, otherKeys.selfSigningKey()
-                                ?.unpaddedBase64PublicKey
-                                ?: ""
-                        )
-                )
-
-        // Check  bob's device is signed by bob's SSK
-        try {
-            olmUtility!!.verifyEd25519Signature(otherSSKSignature, otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, otherDevice.canonicalSignable())
-        } catch (e: Throwable) {
-            return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.InvalidDeviceSignature(otherDeviceId, otherSSKSignature, e))
-        }
-
-        return DeviceTrustResult.Success(DeviceTrustLevel(crossSigningVerified = true, locallyVerified = locallyTrusted))
-    }
-
-    fun checkDeviceTrust(myKeys: MXCrossSigningInfo?, otherKeys: MXCrossSigningInfo?, otherDevice: CryptoDeviceInfo): DeviceTrustResult {
-        val locallyTrusted = otherDevice.trustLevel?.isLocallyVerified()
-        myKeys ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(userId))
-
-        if (!myKeys.isTrusted()) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(myKeys))
-
-        otherKeys ?: return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.CrossSigningNotConfigured(otherDevice.userId))
-
-        // TODO should we force verification ?
-        if (!otherKeys.isTrusted()) return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.KeysNotTrusted(otherKeys))
-
-        // Check if the trust chain is valid
-        /*
-         *  ┏━━━━━━━━┓                             ┏━━━━━━━━┓
-         *  ┃ ALICE  ┃                             ┃  BOB   ┃
-         *  ┗━━━━━━━━┛                             ┗━━━━━━━━┛
-         *   MSK                      ┌────────────▶MSK
-         *                            │
-         *     │                      │               │
-         *     │    SSK               │               └──▶ SSK  ──────────────────┐
-         *     │                      │                                           │
-         *     │                      │                    USK                    │
-         *     └──▶ USK   ────────────┘              (not visible by              │
-         *                                                Alice)                  │
-         *                                                                        ▼
-         *                                                                ┌──────────────┐
-         *                                                                │ BOB's Device │
-         *                                                                └──────────────┘
-         */
-
-        val otherSSKSignature = otherDevice.signatures?.get(otherKeys.userId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}")
-                ?: return legacyFallbackTrust(
-                        locallyTrusted,
-                        DeviceTrustResult.MissingDeviceSignature(
-                                otherDevice.deviceId, otherKeys.selfSigningKey()
-                                ?.unpaddedBase64PublicKey
-                                ?: ""
-                        )
-                )
-
-        // Check  bob's device is signed by bob's SSK
-        try {
-            olmUtility!!.verifyEd25519Signature(otherSSKSignature, otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, otherDevice.canonicalSignable())
-        } catch (e: Throwable) {
-            return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.InvalidDeviceSignature(otherDevice.deviceId, otherSSKSignature, e))
-        }
-
-        return DeviceTrustResult.Success(DeviceTrustLevel(crossSigningVerified = true, locallyVerified = locallyTrusted))
-    }
-
-    private fun legacyFallbackTrust(locallyTrusted: Boolean?, crossSignTrustFail: DeviceTrustResult): DeviceTrustResult {
-        return if (locallyTrusted == true) {
-            DeviceTrustResult.Success(DeviceTrustLevel(crossSigningVerified = false, locallyVerified = true))
-        } else {
-            crossSignTrustFail
-        }
-    }
-
-    override fun onUsersDeviceUpdate(userIds: List<String>) {
-        Timber.d("## CrossSigning - onUsersDeviceUpdate for users: ${userIds.logLimit()}")
-        val workerParams = UpdateTrustWorker.Params(
-                sessionId = sessionId,
-                filename = updateTrustWorkerDataRepository.createParam(userIds)
-        )
-        val workerData = WorkerParamsFactory.toData(workerParams)
-
-        val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<UpdateTrustWorker>()
-                .setInputData(workerData)
-                .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
-                .build()
-
-        workManagerProvider.workManager
-                .beginUniqueWork("TRUST_UPDATE_QUEUE", ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)
-                .enqueue()
-    }
-
-    private fun setUserKeysAsTrusted(otherUserId: String, trusted: Boolean) {
-        val currentTrust = cryptoStore.getCrossSigningInfo(otherUserId)?.isTrusted()
-        cryptoStore.setUserKeysAsTrusted(otherUserId, trusted)
-        // If it's me, recheck trust of all users and devices?
-        val users = ArrayList<String>()
-        if (otherUserId == userId && currentTrust != trusted) {
-            // notify key requester
-            outgoingKeyRequestManager.onSelfCrossSigningTrustChanged(trusted)
-            cryptoStore.updateUsersTrust {
-                users.add(it)
-                checkUserTrust(it).isVerified()
-            }
-
-            users.forEach {
-                cryptoStore.getUserDeviceList(it)?.forEach { device ->
-                    val updatedTrust = checkDeviceTrust(it, device.deviceId, device.trustLevel?.isLocallyVerified() ?: false)
-                    Timber.v("## CrossSigning - update trust for device ${device.deviceId} of user $otherUserId , verified=$updatedTrust")
-                    cryptoStore.setDeviceTrust(it, device.deviceId, updatedTrust.isCrossSignedVerified(), updatedTrust.isLocallyVerified())
-                }
-            }
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
deleted file mode 100644
index 74f0f5745d..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.crosssigning
-
-import android.content.Context
-import androidx.work.WorkerParameters
-import com.squareup.moshi.JsonClass
-import io.realm.Realm
-import io.realm.RealmConfiguration
-import io.realm.kotlin.where
-import org.matrix.android.sdk.api.extensions.orFalse
-import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
-import org.matrix.android.sdk.api.session.crypto.crosssigning.UserTrustResult
-import org.matrix.android.sdk.api.session.crypto.crosssigning.isCrossSignedVerified
-import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
-import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
-import org.matrix.android.sdk.internal.SessionManager
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper
-import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields
-import org.matrix.android.sdk.internal.crypto.store.db.model.CryptoMapper
-import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
-import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
-import org.matrix.android.sdk.internal.database.awaitTransaction
-import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
-import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
-import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
-import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
-import org.matrix.android.sdk.internal.database.query.where
-import org.matrix.android.sdk.internal.di.CryptoDatabase
-import org.matrix.android.sdk.internal.di.SessionDatabase
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.session.SessionComponent
-import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
-import org.matrix.android.sdk.internal.util.logLimit
-import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker
-import org.matrix.android.sdk.internal.worker.SessionWorkerParams
-import timber.log.Timber
-import javax.inject.Inject
-
-internal class UpdateTrustWorker(context: Context, params: WorkerParameters, sessionManager: SessionManager) :
-        SessionSafeCoroutineWorker<UpdateTrustWorker.Params>(context, params, sessionManager, Params::class.java) {
-
-    @JsonClass(generateAdapter = true)
-    internal data class Params(
-            override val sessionId: String,
-            override val lastFailureMessage: String? = null,
-            // Kept for compatibility, but not used anymore (can be used for pending Worker)
-            val updatedUserIds: List<String>? = null,
-            // Passing a long list of userId can break the Work Manager due to data size limitation.
-            // so now we use a temporary file to store the data
-            val filename: String? = null
-    ) : SessionWorkerParams
-
-    @Inject lateinit var crossSigningService: DefaultCrossSigningService
-
-    // It breaks the crypto store contract, but we need to batch things :/
-    @CryptoDatabase
-    @Inject lateinit var cryptoRealmConfiguration: RealmConfiguration
-
-    @SessionDatabase
-    @Inject lateinit var sessionRealmConfiguration: RealmConfiguration
-
-    @UserId
-    @Inject lateinit var myUserId: String
-    @Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper
-    @Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
-
-    //    @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater
-    @Inject lateinit var cryptoStore: IMXCryptoStore
-
-    override fun injectWith(injector: SessionComponent) {
-        injector.inject(this)
-    }
-
-    override suspend fun doSafeWork(params: Params): Result {
-        val userList = params.filename
-                ?.let { updateTrustWorkerDataRepository.getParam(it) }
-                ?.userIds
-                ?: params.updatedUserIds.orEmpty()
-
-        // List should not be empty, but let's avoid go further in case of empty list
-        if (userList.isNotEmpty()) {
-            // Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user,
-            // or a new device?) So we check all again :/
-            Timber.v("## CrossSigning - Updating trust for users: ${userList.logLimit()}")
-            updateTrust(userList)
-        }
-
-        cleanup(params)
-        return Result.success()
-    }
-
-    private suspend fun updateTrust(userListParam: List<String>) {
-        var userList = userListParam
-        var myCrossSigningInfo: MXCrossSigningInfo? = null
-
-        // First we check that the users MSK are trusted by mine
-        // After that we check the trust chain for each devices of each users
-        awaitTransaction(cryptoRealmConfiguration) { cryptoRealm ->
-            // By mapping here to model, this object is not live
-            // I should update it if needed
-            myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
-
-            var myTrustResult: UserTrustResult? = null
-
-            if (userList.contains(myUserId)) {
-                Timber.d("## CrossSigning - Clear all trust as a change on my user was detected")
-                // i am in the list.. but i don't know exactly the delta of change :/
-                // If it's my cross signing keys we should refresh all trust
-                // do it anyway ?
-                userList = cryptoRealm.where(CrossSigningInfoEntity::class.java)
-                        .findAll()
-                        .mapNotNull { it.userId }
-
-                // check right now my keys and mark it as trusted as other trust depends on it
-                val myDevices = cryptoRealm.where<UserEntity>()
-                        .equalTo(UserEntityFields.USER_ID, myUserId)
-                        .findFirst()
-                        ?.devices
-                        ?.map { CryptoMapper.mapToModel(it) }
-
-                myTrustResult = crossSigningService.checkSelfTrust(myCrossSigningInfo, myDevices)
-                updateCrossSigningKeysTrust(cryptoRealm, myUserId, myTrustResult.isVerified())
-                // update model reference
-                myCrossSigningInfo = getCrossSigningInfo(cryptoRealm, myUserId)
-            }
-
-            val otherInfos = userList.associateWith { userId ->
-                getCrossSigningInfo(cryptoRealm, userId)
-            }
-
-            val trusts = otherInfos.mapValues { entry ->
-                when (entry.key) {
-                    myUserId -> myTrustResult
-                    else     -> {
-                        crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also {
-                            Timber.v("## CrossSigning - user:${entry.key} result:$it")
-                        }
-                    }
-                }
-            }
-
-            // TODO! if it's me and my keys has changed... I have to reset trust for everyone!
-            // i have all the new trusts, update DB
-            trusts.forEach {
-                val verified = it.value?.isVerified() == true
-                updateCrossSigningKeysTrust(cryptoRealm, it.key, verified)
-            }
-
-            // Ok so now we have to check device trust for all these users..
-            Timber.v("## CrossSigning - Updating devices cross trust users: ${trusts.keys.logLimit()}")
-            trusts.keys.forEach { userId ->
-                val devicesEntities = cryptoRealm.where<UserEntity>()
-                        .equalTo(UserEntityFields.USER_ID, userId)
-                        .findFirst()
-                        ?.devices
-
-                val trustMap = devicesEntities?.associateWith { device ->
-                    // get up to date from DB has could have been updated
-                    val otherInfo = getCrossSigningInfo(cryptoRealm, userId)
-                    crossSigningService.checkDeviceTrust(myCrossSigningInfo, otherInfo, CryptoMapper.mapToModel(device))
-                }
-
-                // Update trust if needed
-                devicesEntities?.forEach { device ->
-                    val crossSignedVerified = trustMap?.get(device)?.isCrossSignedVerified()
-                    Timber.v("## CrossSigning - Trust for ${device.userId}|${device.deviceId} : cross verified: ${trustMap?.get(device)}")
-                    if (device.trustLevelEntity?.crossSignedVerified != crossSignedVerified) {
-                        Timber.d("## CrossSigning - Trust change detected for ${device.userId}|${device.deviceId} : cross verified: $crossSignedVerified")
-                        // need to save
-                        val trustEntity = device.trustLevelEntity
-                        if (trustEntity == null) {
-                            device.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
-                                it.locallyVerified = false
-                                it.crossSignedVerified = crossSignedVerified
-                            }
-                        } else {
-                            trustEntity.crossSignedVerified = crossSignedVerified
-                        }
-                    }
-                }
-            }
-        }
-
-        // So Cross Signing keys trust is updated, device trust is updated
-        // We can now update room shields? in the session DB?
-        updateTrustStep2(userList, myCrossSigningInfo)
-    }
-
-    private suspend fun updateTrustStep2(userList: List<String>, myCrossSigningInfo: MXCrossSigningInfo?) {
-        Timber.d("## CrossSigning - Updating shields for impacted rooms...")
-        awaitTransaction(sessionRealmConfiguration) { sessionRealm ->
-            Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
-                sessionRealm.where(RoomMemberSummaryEntity::class.java)
-                        .`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
-                        .distinct(RoomMemberSummaryEntityFields.ROOM_ID)
-                        .findAll()
-                        .map { it.roomId }
-                        .also { Timber.d("## CrossSigning -  ... impacted rooms ${it.logLimit()}") }
-                        .forEach { roomId ->
-                            RoomSummaryEntity.where(sessionRealm, roomId)
-                                    .equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true)
-                                    .findFirst()
-                                    ?.let { roomSummary ->
-                                        Timber.v("## CrossSigning - Check shield state for room $roomId")
-                                        val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds()
-                                        try {
-                                            val updatedTrust = computeRoomShield(
-                                                    myCrossSigningInfo,
-                                                    cryptoRealm,
-                                                    allActiveRoomMembers,
-                                                    roomSummary
-                                            )
-                                            if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
-                                                Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
-                                                roomSummary.roomEncryptionTrustLevel = updatedTrust
-                                            }
-                                        } catch (failure: Throwable) {
-                                            Timber.e(failure)
-                                        }
-                                    }
-                        }
-            }
-        }
-    }
-
-    private fun getCrossSigningInfo(cryptoRealm: Realm, userId: String): MXCrossSigningInfo? {
-        return cryptoRealm.where(CrossSigningInfoEntity::class.java)
-                .equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
-                .findFirst()
-                ?.let { mapCrossSigningInfoEntity(it) }
-    }
-
-    private fun cleanup(params: Params) {
-        params.filename
-                ?.let { updateTrustWorkerDataRepository.delete(it) }
-    }
-
-    private fun updateCrossSigningKeysTrust(cryptoRealm: Realm, userId: String, verified: Boolean) {
-        cryptoRealm.where(CrossSigningInfoEntity::class.java)
-                .equalTo(CrossSigningInfoEntityFields.USER_ID, userId)
-                .findFirst()
-                ?.crossSigningKeys
-                ?.forEach { info ->
-                    // optimization to avoid trigger updates when there is no change..
-                    if (info.trustLevelEntity?.isVerified() != verified) {
-                        Timber.d("## CrossSigning - Trust change for $userId : $verified")
-                        val level = info.trustLevelEntity
-                        if (level == null) {
-                            info.trustLevelEntity = cryptoRealm.createObject(TrustLevelEntity::class.java).also {
-                                it.locallyVerified = verified
-                                it.crossSignedVerified = verified
-                            }
-                        } else {
-                            level.locallyVerified = verified
-                            level.crossSignedVerified = verified
-                        }
-                    }
-                }
-    }
-
-    private fun computeRoomShield(myCrossSigningInfo: MXCrossSigningInfo?,
-                                  cryptoRealm: Realm,
-                                  activeMemberUserIds: List<String>,
-                                  roomSummaryEntity: RoomSummaryEntity): RoomEncryptionTrustLevel {
-        Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} -> ${activeMemberUserIds.logLimit()}")
-        // The set of “all users” depends on the type of room:
-        // For regular / topic rooms which have more than 2 members (including yourself) are considered when decorating a room
-        // For 1:1 and group DM rooms, all other users (i.e. excluding yourself) are considered when decorating a room
-        val listToCheck = if (roomSummaryEntity.isDirect || activeMemberUserIds.size <= 2) {
-            activeMemberUserIds.filter { it != myUserId }
-        } else {
-            activeMemberUserIds
-        }
-
-        val allTrustedUserIds = listToCheck
-                .filter { userId ->
-                    getCrossSigningInfo(cryptoRealm, userId)?.isTrusted() == true
-                }
-
-        return if (allTrustedUserIds.isEmpty()) {
-            RoomEncryptionTrustLevel.Default
-        } else {
-            // If one of the verified user as an untrusted device -> warning
-            // If all devices of all verified users are trusted -> green
-            // else -> black
-            allTrustedUserIds
-                    .mapNotNull { userId ->
-                        cryptoRealm.where<UserEntity>()
-                                .equalTo(UserEntityFields.USER_ID, userId)
-                                .findFirst()
-                                ?.devices
-                                ?.map { CryptoMapper.mapToModel(it) }
-                    }
-                    .flatten()
-                    .let { allDevices ->
-                        Timber.v("## CrossSigning - computeRoomShield ${roomSummaryEntity.roomId} devices ${allDevices.map { it.deviceId }.logLimit()}")
-                        if (myCrossSigningInfo != null) {
-                            allDevices.any { !it.trustLevel?.crossSigningVerified.orFalse() }
-                        } else {
-                            // Legacy method
-                            allDevices.any { !it.isVerified }
-                        }
-                    }
-                    .let { hasWarning ->
-                        if (hasWarning) {
-                            RoomEncryptionTrustLevel.Warning
-                        } else {
-                            if (listToCheck.size == allTrustedUserIds.size) {
-                                // all users are trusted and all devices are verified
-                                RoomEncryptionTrustLevel.Trusted
-                            } else {
-                                RoomEncryptionTrustLevel.Default
-                            }
-                        }
-                    }
-        }
-    }
-
-    private fun mapCrossSigningInfoEntity(xsignInfo: CrossSigningInfoEntity): MXCrossSigningInfo {
-        val userId = xsignInfo.userId ?: ""
-        return MXCrossSigningInfo(
-                userId = userId,
-                crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull {
-                    crossSigningKeysMapper.map(userId, it)
-                }
-        )
-    }
-
-    override fun buildErrorParams(params: Params, message: String): Params {
-        return params.copy(lastFailureMessage = params.lastFailureMessage ?: message)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt
index 72aeece896..37ef4ea29b 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/RustKeyBackupService.kt
@@ -28,31 +28,33 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
+import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
 import org.matrix.android.sdk.api.listeners.ProgressListener
 import org.matrix.android.sdk.api.listeners.StepProgressListener
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupLastVersionResult
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
-import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
+import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
+import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
+import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
+import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
+import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
 import org.matrix.android.sdk.internal.crypto.MegolmSessionData
 import org.matrix.android.sdk.internal.crypto.MegolmSessionImportManager
 import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeyBackupData
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
-import org.matrix.android.sdk.internal.crypto.model.ImportRoomKeysResult
 import org.matrix.android.sdk.internal.crypto.network.RequestSender
-import org.matrix.android.sdk.internal.crypto.store.SavedKeyBackupKeyInfo
 import org.matrix.android.sdk.internal.di.MoshiProvider
 import org.matrix.android.sdk.internal.session.SessionScope
 import org.matrix.android.sdk.internal.util.JsonCanonicalizer
@@ -263,7 +265,7 @@ internal class RustKeyBackupService @Inject constructor(
     private suspend fun checkBackupTrust(authData: MegolmBackupAuthData?): KeysBackupVersionTrust {
         return if (authData == null || authData.publicKey.isEmpty() || authData.signatures.isNullOrEmpty()) {
             Timber.v("getKeysBackupTrust: Key backup is absent or missing required data")
-            KeysBackupVersionTrust()
+            KeysBackupVersionTrust(usable = false)
         } else {
             KeysBackupVersionTrust(olmMachine.checkAuthDataSignature(authData))
         }
@@ -375,7 +377,7 @@ internal class RustKeyBackupService @Inject constructor(
         Timber.i("## CrossSigning - onSecretKeyGossip")
         withContext(coroutineDispatchers.crypto) {
             try {
-                val version = sender.getKeyBackupVersion()
+                val version = sender.getKeyBackupLastVersion()?.toKeysVersionResult()
 
                 if (version != null) {
                     val key = BackupRecoveryKey.fromBase64(secret)
@@ -584,13 +586,13 @@ internal class RustKeyBackupService @Inject constructor(
     }
 
     @Throws
-    override suspend fun getCurrentVersion(): KeysVersionResult? {
-        return sender.getKeyBackupVersion()
+    override suspend fun getCurrentVersion(): KeysBackupLastVersionResult? {
+        return sender.getKeyBackupLastVersion()
     }
 
     override suspend fun forceUsingLastVersion(): Boolean {
         val response = withContext(coroutineDispatchers.io) {
-            sender.getKeyBackupVersion()
+            sender.getKeyBackupLastVersion()?.toKeysVersionResult()
         }
 
         return withContext(coroutineDispatchers.crypto) {
@@ -644,7 +646,7 @@ internal class RustKeyBackupService @Inject constructor(
             keysBackupVersion = null
             keysBackupStateManager.state = KeysBackupState.CheckingBackUpOnHomeserver
             try {
-                val data = getCurrentVersion()
+                val data = getCurrentVersion()?.toKeysVersionResult()
                 withContext(coroutineDispatchers.crypto) {
                     checkAndStartWithKeysBackupVersion(data)
                 }
@@ -718,6 +720,10 @@ internal class RustKeyBackupService @Inject constructor(
         }
     }
 
+    override fun computePrivateKey(passphrase: String, privateKeySalt: String, privateKeyIterations: Int, progressListener: ProgressListener): ByteArray {
+        return deriveKey(passphrase, privateKeySalt, privateKeyIterations, progressListener)
+    }
+
     override suspend fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? {
         val info = olmMachine.getBackupKeys() ?: return null
         return SavedKeyBackupKeyInfo(info.recoveryKey, info.backupVersion)
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt
index d1ec8e5589..195a2d5e9a 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt
@@ -23,8 +23,8 @@ import kotlinx.coroutines.joinAll
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
-import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
 import org.matrix.android.sdk.api.logger.LoggerTag
+import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
 import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider
 import org.matrix.android.sdk.internal.crypto.OlmMachine
 import timber.log.Timber
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt
index fac164544a..04251ca9c4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/network/RequestSender.kt
@@ -22,15 +22,18 @@ import dagger.Lazy
 import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.MatrixError
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupLastVersionResult
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
+import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
 import org.matrix.android.sdk.api.session.events.model.Content
 import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.uia.UiaResult
 import org.matrix.android.sdk.api.util.JsonDict
 import org.matrix.android.sdk.internal.auth.registration.handleUIA
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersion
-import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.UpdateKeysBackupVersionBody
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.CreateKeysBackupVersionTask
@@ -42,7 +45,6 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetRoomSessionsDa
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.GetSessionsDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.StoreSessionsDataTask
 import org.matrix.android.sdk.internal.crypto.keysbackup.tasks.UpdateKeysBackupVersionTask
-import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap
 import org.matrix.android.sdk.internal.crypto.model.rest.KeysClaimResponse
 import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
 import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse
@@ -177,7 +179,7 @@ internal class RequestSender @Inject constructor(
             uploadSigningKeysTask.execute(uploadSigningKeysParams)
         } catch (failure: Throwable) {
             if (interactiveAuthInterceptor == null ||
-                    !handleUIA(
+                    handleUIA(
                             failure = failure,
                             interceptor = interactiveAuthInterceptor,
                             retryBlock = { authUpdate ->
@@ -186,7 +188,7 @@ internal class RequestSender @Inject constructor(
                                         REQUEST_RETRY_COUNT
                                 )
                             }
-                    )
+                    ) != UiaResult.SUCCESS
             ) {
                 Timber.d("## UIA: propagate failure")
                 throw failure
@@ -217,13 +219,17 @@ internal class RequestSender @Inject constructor(
         sendToDeviceTask.executeRetry(sendToDeviceParams, REQUEST_RETRY_COUNT)
     }
 
-    suspend fun getKeyBackupVersion(version: String? = null): KeysVersionResult? {
+    suspend fun getKeyBackupVersion(version: String): KeysVersionResult? = getKeyBackupVersion {
+        getKeysBackupVersionTask.executeRetry(version, 3)
+    }
+
+    suspend fun getKeyBackupLastVersion(): KeysBackupLastVersionResult? = getKeyBackupVersion {
+        getKeysBackupLastVersionTask.executeRetry(Unit, 3)
+    }
+
+    private inline fun <reified T> getKeyBackupVersion(block: ()-> T?): T?{
         return try {
-            if (version != null) {
-                getKeysBackupVersionTask.executeRetry(version, 3)
-            } else {
-                getKeysBackupLastVersionTask.executeRetry(Unit, 3)
-            }
+            block()
         } catch (failure: Throwable) {
             if (failure is Failure.ServerError &&
                     failure.error.code == MatrixError.M_NOT_FOUND) {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt
deleted file mode 100644
index 53190c43ff..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.tasks
-
-import dagger.Lazy
-import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
-import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
-import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage
-import org.matrix.android.sdk.api.session.uia.UiaResult
-import org.matrix.android.sdk.api.util.toBase64NoPadding
-import org.matrix.android.sdk.internal.auth.registration.handleUIA
-import org.matrix.android.sdk.internal.crypto.MXOlmDevice
-import org.matrix.android.sdk.internal.crypto.MyDeviceInfoHolder
-import org.matrix.android.sdk.internal.crypto.crosssigning.canonicalSignable
-import org.matrix.android.sdk.internal.crypto.model.rest.UploadSignatureQueryBuilder
-import org.matrix.android.sdk.internal.di.UserId
-import org.matrix.android.sdk.internal.task.Task
-import org.matrix.android.sdk.internal.util.JsonCanonicalizer
-import org.matrix.olm.OlmPkSigning
-import timber.log.Timber
-import javax.inject.Inject
-
-internal interface InitializeCrossSigningTask : Task<InitializeCrossSigningTask.Params, InitializeCrossSigningTask.Result> {
-    data class Params(
-            val interactiveAuthInterceptor: UserInteractiveAuthInterceptor?
-    )
-
-    data class Result(
-            val masterKeyPK: String,
-            val userKeyPK: String,
-            val selfSigningKeyPK: String,
-            val masterKeyInfo: CryptoCrossSigningKey,
-            val userKeyInfo: CryptoCrossSigningKey,
-            val selfSignedKeyInfo: CryptoCrossSigningKey
-    )
-}
-
-internal class DefaultInitializeCrossSigningTask @Inject constructor(
-        @UserId private val userId: String,
-        private val olmDevice: MXOlmDevice,
-        private val myDeviceInfoHolder: Lazy<MyDeviceInfoHolder>,
-        private val uploadSigningKeysTask: UploadSigningKeysTask,
-        private val uploadSignaturesTask: UploadSignaturesTask
-) : InitializeCrossSigningTask {
-
-    override suspend fun execute(params: InitializeCrossSigningTask.Params): InitializeCrossSigningTask.Result {
-        var masterPkOlm: OlmPkSigning? = null
-        var userSigningPkOlm: OlmPkSigning? = null
-        var selfSigningPkOlm: OlmPkSigning? = null
-
-        try {
-            // =================
-            // MASTER KEY
-            // =================
-
-            masterPkOlm = OlmPkSigning()
-            val masterKeyPrivateKey = OlmPkSigning.generateSeed()
-            val masterPublicKey = masterPkOlm.initWithSeed(masterKeyPrivateKey)
-
-            Timber.v("## CrossSigning - masterPublicKey:$masterPublicKey")
-
-            // =================
-            // USER KEY
-            // =================
-            userSigningPkOlm = OlmPkSigning()
-            val uskPrivateKey = OlmPkSigning.generateSeed()
-            val uskPublicKey = userSigningPkOlm.initWithSeed(uskPrivateKey)
-
-            Timber.v("## CrossSigning - uskPublicKey:$uskPublicKey")
-
-            // Sign userSigningKey with master
-            val signedUSK = CryptoCrossSigningKey.Builder(userId, KeyUsage.USER_SIGNING)
-                    .key(uskPublicKey)
-                    .build()
-                    .canonicalSignable()
-                    .let { masterPkOlm.sign(it) }
-
-            // =================
-            // SELF SIGNING KEY
-            // =================
-            selfSigningPkOlm = OlmPkSigning()
-            val sskPrivateKey = OlmPkSigning.generateSeed()
-            val sskPublicKey = selfSigningPkOlm.initWithSeed(sskPrivateKey)
-
-            Timber.v("## CrossSigning - sskPublicKey:$sskPublicKey")
-
-            // Sign selfSigningKey with master
-            val signedSSK = CryptoCrossSigningKey.Builder(userId, KeyUsage.SELF_SIGNING)
-                    .key(sskPublicKey)
-                    .build()
-                    .canonicalSignable()
-                    .let { masterPkOlm.sign(it) }
-
-            // I need to upload the keys
-            val mskCrossSigningKeyInfo = CryptoCrossSigningKey.Builder(userId, KeyUsage.MASTER)
-                    .key(masterPublicKey)
-                    .build()
-            val uploadSigningKeysParams = UploadSigningKeysTask.Params(
-                    masterKey = mskCrossSigningKeyInfo,
-                    userKey = CryptoCrossSigningKey.Builder(userId, KeyUsage.USER_SIGNING)
-                            .key(uskPublicKey)
-                            .signature(userId, masterPublicKey, signedUSK)
-                            .build(),
-                    selfSignedKey = CryptoCrossSigningKey.Builder(userId, KeyUsage.SELF_SIGNING)
-                            .key(sskPublicKey)
-                            .signature(userId, masterPublicKey, signedSSK)
-                            .build(),
-                    userAuthParam = null
-//                    userAuthParam = params.authParams
-            )
-
-            try {
-                uploadSigningKeysTask.execute(uploadSigningKeysParams)
-            } catch (failure: Throwable) {
-                if (params.interactiveAuthInterceptor == null ||
-                        handleUIA(
-                                failure = failure,
-                                interceptor = params.interactiveAuthInterceptor,
-                                retryBlock = { authUpdate ->
-                                    uploadSigningKeysTask.execute(uploadSigningKeysParams.copy(userAuthParam = authUpdate))
-                                }
-                        ) != UiaResult.SUCCESS
-                ) {
-                    Timber.d("## UIA: propagate failure")
-                    throw failure
-                }
-            }
-
-            //  Sign the current device with SSK
-            val uploadSignatureQueryBuilder = UploadSignatureQueryBuilder()
-
-            val myDevice = myDeviceInfoHolder.get().myDevice
-            val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, myDevice.signalableJSONDictionary())
-            val signedDevice = selfSigningPkOlm.sign(canonicalJson)
-            val updateSignatures = (myDevice.signatures?.toMutableMap() ?: HashMap())
-                    .also {
-                        it[userId] = (it[userId]
-                                ?: HashMap()) + mapOf("ed25519:$sskPublicKey" to signedDevice)
-                    }
-            myDevice.copy(signatures = updateSignatures).let {
-                uploadSignatureQueryBuilder.withDeviceInfo(it)
-            }
-
-            // sign MSK with device key (migration) and upload signatures
-            val message = JsonCanonicalizer.getCanonicalJson(Map::class.java, mskCrossSigningKeyInfo.signalableJSONDictionary())
-            olmDevice.signMessage(message)?.let { sign ->
-                val mskUpdatedSignatures = (mskCrossSigningKeyInfo.signatures?.toMutableMap()
-                        ?: HashMap()).also {
-                    it[userId] = (it[userId]
-                            ?: HashMap()) + mapOf("ed25519:${myDevice.deviceId}" to sign)
-                }
-                mskCrossSigningKeyInfo.copy(
-                        signatures = mskUpdatedSignatures
-                ).let {
-                    uploadSignatureQueryBuilder.withSigningKeyInfo(it)
-                }
-            }
-
-            // TODO should we ignore failure of that?
-            uploadSignaturesTask.execute(UploadSignaturesTask.Params(uploadSignatureQueryBuilder.build()))
-
-            return InitializeCrossSigningTask.Result(
-                    masterKeyPK = masterKeyPrivateKey.toBase64NoPadding(),
-                    userKeyPK = uskPrivateKey.toBase64NoPadding(),
-                    selfSigningKeyPK = sskPrivateKey.toBase64NoPadding(),
-                    masterKeyInfo = uploadSigningKeysParams.masterKey,
-                    userKeyInfo = uploadSigningKeysParams.userKey,
-                    selfSignedKeyInfo = uploadSigningKeysParams.selfSignedKey
-            )
-        } finally {
-            masterPkOlm?.releaseSigning()
-            userSigningPkOlm?.releaseSigning()
-            selfSigningPkOlm?.releaseSigning()
-        }
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
deleted file mode 100644
index a51fdea9f2..0000000000
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2020 The Matrix.org Foundation C.I.C.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.matrix.android.sdk.internal.crypto.verification.qrcode
-
-import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService
-import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
-import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
-import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
-import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.api.util.fromBase64
-import org.matrix.android.sdk.internal.crypto.OutgoingKeyRequestManager
-import org.matrix.android.sdk.internal.crypto.SecretShareManager
-import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
-import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64Safe
-import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
-import org.matrix.android.sdk.internal.crypto.verification.ValidVerificationInfoStart
-import timber.log.Timber
-
-internal class DefaultQrCodeVerificationTransaction(
-        setDeviceVerificationAction: SetDeviceVerificationAction,
-        override val transactionId: String,
-        override val otherUserId: String,
-        override var otherDeviceId: String?,
-        private val crossSigningService: CrossSigningService,
-        outgoingKeyRequestManager: OutgoingKeyRequestManager,
-        secretShareManager: SecretShareManager,
-        private val cryptoStore: IMXCryptoStore,
-        // Not null only if other user is able to scan QR code
-        private val qrCodeData: QrCodeData?,
-        val userId: String,
-        val deviceId: String,
-        override val isIncoming: Boolean
-) : DefaultVerificationTransaction(
-        setDeviceVerificationAction,
-        crossSigningService,
-        outgoingKeyRequestManager,
-        secretShareManager,
-        userId,
-        transactionId,
-        otherUserId,
-        otherDeviceId,
-        isIncoming
-),
-        QrCodeVerificationTransaction {
-
-    override val qrCodeText: String?
-        get() = qrCodeData?.toEncodedString()
-
-    override var state: VerificationTxState = VerificationTxState.None
-        set(newState) {
-            field = newState
-
-            listeners.forEach {
-                try {
-                    it.transactionUpdated(this)
-                } catch (e: Throwable) {
-                    Timber.e(e, "## Error while notifying listeners")
-                }
-            }
-        }
-
-    override fun userHasScannedOtherQrCode(otherQrCodeText: String) {
-        val otherQrCodeData = otherQrCodeText.toQrCodeData() ?: run {
-            Timber.d("## Verification QR: Invalid QR Code Data")
-            cancel(CancelCode.QrCodeInvalid)
-            return
-        }
-
-        // Perform some checks
-        if (otherQrCodeData.transactionId != transactionId) {
-            Timber.d("## Verification QR: Invalid transaction actual ${otherQrCodeData.transactionId} expected:$transactionId")
-            cancel(CancelCode.QrCodeInvalid)
-            return
-        }
-
-        // check master key
-        val myMasterKey = crossSigningService.getUserCrossSigningKeys(userId)?.masterKey()?.unpaddedBase64PublicKey
-        var canTrustOtherUserMasterKey = false
-
-        // Check the other device view of my MSK
-        when (otherQrCodeData) {
-            is QrCodeData.VerifyingAnotherUser             -> {
-                // key2 (aka otherUserMasterCrossSigningPublicKey) is what the one displaying the QR code (other user) think my MSK is.
-                // Let's check that it's correct
-                // If not -> Cancel
-                if (otherQrCodeData.otherUserMasterCrossSigningPublicKey != myMasterKey) {
-                    Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.otherUserMasterCrossSigningPublicKey}")
-                    cancel(CancelCode.MismatchedKeys)
-                    return
-                } else Unit
-            }
-            is QrCodeData.SelfVerifyingMasterKeyTrusted    -> {
-                // key1 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
-                // Let's check that I see the same MSK
-                // If not -> Cancel
-                if (otherQrCodeData.userMasterCrossSigningPublicKey != myMasterKey) {
-                    Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
-                    cancel(CancelCode.MismatchedKeys)
-                    return
-                } else {
-                    // I can trust the MSK then (i see the same one, and other session tell me it's trusted by him)
-                    canTrustOtherUserMasterKey = true
-                }
-            }
-            is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
-                // key2 (aka userMasterCrossSigningPublicKey) is the session displaying the QR code view of our MSK.
-                // Let's check that it's the good one
-                // If not -> Cancel
-                if (otherQrCodeData.userMasterCrossSigningPublicKey != myMasterKey) {
-                    Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
-                    cancel(CancelCode.MismatchedKeys)
-                    return
-                } else {
-                    // Nothing special here, we will send a reciprocate start event, and then the other session will trust it's view of the MSK
-                }
-            }
-        }
-
-        val toVerifyDeviceIds = mutableListOf<String>()
-
-        // Let's now check the other user/device key material
-        when (otherQrCodeData) {
-            is QrCodeData.VerifyingAnotherUser             -> {
-                // key1(aka userMasterCrossSigningPublicKey) is the MSK of the one displaying the QR code (i.e other user)
-                // Let's check that it matches what I think it should be
-                if (otherQrCodeData.userMasterCrossSigningPublicKey
-                        != crossSigningService.getUserCrossSigningKeys(otherUserId)?.masterKey()?.unpaddedBase64PublicKey) {
-                    Timber.d("## Verification QR: Invalid user master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
-                    cancel(CancelCode.MismatchedKeys)
-                    return
-                } else {
-                    // It does so i should mark it as trusted
-                    canTrustOtherUserMasterKey = true
-                    Unit
-                }
-            }
-            is QrCodeData.SelfVerifyingMasterKeyTrusted    -> {
-                // key2 (aka otherDeviceKey) is my current device key in POV of the one displaying the QR code (i.e other device)
-                // Let's check that it's correct
-                if (otherQrCodeData.otherDeviceKey
-                        != cryptoStore.getUserDevice(userId, deviceId)?.fingerprint()) {
-                    Timber.d("## Verification QR: Invalid other device key ${otherQrCodeData.otherDeviceKey}")
-                    cancel(CancelCode.MismatchedKeys)
-                    return
-                } else Unit // Nothing special here, we will send a reciprocate start event, and then the other session will trust my device
-                // and thus allow me to request SSSS secret
-            }
-            is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
-                // key1 (aka otherDeviceKey) is the device key of the one displaying the QR code (i.e other device)
-                // Let's check that it matches what I have locally
-                if (otherQrCodeData.deviceKey
-                        != cryptoStore.getUserDevice(otherUserId, otherDeviceId ?: "")?.fingerprint()) {
-                    Timber.d("## Verification QR: Invalid device key ${otherQrCodeData.deviceKey}")
-                    cancel(CancelCode.MismatchedKeys)
-                    return
-                } else {
-                    // Yes it does -> i should trust it and sign then upload the signature
-                    toVerifyDeviceIds.add(otherDeviceId ?: "")
-                    Unit
-                }
-            }
-        }
-
-        if (!canTrustOtherUserMasterKey && toVerifyDeviceIds.isEmpty()) {
-            // Nothing to verify
-            cancel(CancelCode.MismatchedKeys)
-            return
-        }
-
-        // All checks are correct
-        // Send the shared secret so that sender can trust me
-        // qrCodeData.sharedSecret will be used to send the start request
-        start(otherQrCodeData.sharedSecret)
-
-        trust(
-                canTrustOtherUserMasterKey = canTrustOtherUserMasterKey,
-                toVerifyDeviceIds = toVerifyDeviceIds.distinct(),
-                eventuallyMarkMyMasterKeyAsTrusted = true,
-                autoDone = false
-        )
-    }
-
-    private fun start(remoteSecret: String, onDone: (() -> Unit)? = null) {
-        if (state != VerificationTxState.None) {
-            Timber.e("## Verification QR: start verification from invalid state")
-            // should I cancel??
-            throw IllegalStateException("Interactive Key verification already started")
-        }
-
-        state = VerificationTxState.Started
-        val startMessage = transport.createStartForQrCode(
-                deviceId,
-                transactionId,
-                remoteSecret
-        )
-
-        transport.sendToOther(
-                EventType.KEY_VERIFICATION_START,
-                startMessage,
-                VerificationTxState.WaitingOtherReciprocateConfirm,
-                CancelCode.User,
-                onDone
-        )
-    }
-
-    override fun cancel() {
-        cancel(CancelCode.User)
-    }
-
-    override fun cancel(code: CancelCode) {
-        state = VerificationTxState.Cancelled(code, true)
-        transport.cancelTransaction(transactionId, otherUserId, otherDeviceId ?: "", code)
-    }
-
-    override fun isToDeviceTransport() = false
-
-    // Other user has scanned our QR code. check that the secret matched, so we can trust him
-    fun onStartReceived(startReq: ValidVerificationInfoStart.ReciprocateVerificationInfoStart) {
-        if (qrCodeData == null) {
-            // Should not happen
-            cancel(CancelCode.UnexpectedMessage)
-            return
-        }
-
-        if (startReq.sharedSecret.fromBase64Safe()?.contentEquals(qrCodeData.sharedSecret.fromBase64()) == true) {
-            // Ok, we can trust the other user
-            // We can only trust the master key in this case
-            // But first, ask the user for a confirmation
-            state = VerificationTxState.QrScannedByOther
-        } else {
-            // Display a warning
-            cancel(CancelCode.MismatchedKeys)
-        }
-    }
-
-    fun onDoneReceived() {
-        if (state != VerificationTxState.WaitingOtherReciprocateConfirm) {
-            cancel(CancelCode.UnexpectedMessage)
-            return
-        }
-        state = VerificationTxState.Verified
-        transport.done(transactionId) {}
-    }
-
-    override fun otherUserScannedMyQrCode() {
-        when (qrCodeData) {
-            is QrCodeData.VerifyingAnotherUser             -> {
-                // Alice telling Bob that the code was scanned successfully is sufficient for Bob to trust Alice's key,
-                trust(true, emptyList(), false)
-            }
-            is QrCodeData.SelfVerifyingMasterKeyTrusted    -> {
-                // I now know that I have the correct device key for other session,
-                // and can sign it with the self-signing key and upload the signature
-                trust(false, listOf(otherDeviceId ?: ""), false)
-            }
-            is QrCodeData.SelfVerifyingMasterKeyNotTrusted -> {
-                // I now know that i can trust my MSK
-                trust(true, emptyList(), true)
-            }
-            null                                           -> Unit
-        }
-    }
-
-    override fun otherUserDidNotScannedMyQrCode() {
-        // What can I do then?
-        // At least remove the transaction...
-        cancel(CancelCode.MismatchedKeys)
-    }
-}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultToDeviceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultToDeviceService.kt
index 609acdd89c..f61d444925 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultToDeviceService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultToDeviceService.kt
@@ -20,15 +20,14 @@ import org.matrix.android.sdk.api.session.ToDeviceService
 import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
 import org.matrix.android.sdk.api.session.events.model.Content
 import org.matrix.android.sdk.api.session.events.model.EventType
-import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter
+import org.matrix.android.sdk.internal.crypto.EncryptEventContentUseCase
+import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
 import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask
 import javax.inject.Inject
 
 internal class DefaultToDeviceService @Inject constructor(
         private val sendToDeviceTask: SendToDeviceTask,
-        private val messageEncrypter: MessageEncrypter,
-        private val cryptoStore: IMXCryptoStore
 ) : ToDeviceService {
 
     override suspend fun sendToDevice(eventType: String, targets: Map<String, List<String>>, content: Content, txnId: String?) {
@@ -53,6 +52,8 @@ internal class DefaultToDeviceService @Inject constructor(
     }
 
     override suspend fun sendEncryptedToDevice(eventType: String, targets: Map<String, List<String>>, content: Content, txnId: String?) {
+        //TODO: add to rust-ffi
+        /*
         val payloadJson = mapOf(
                 "type" to eventType,
                 "content" to content
@@ -63,11 +64,13 @@ internal class DefaultToDeviceService @Inject constructor(
         targets.forEach { (userId, deviceIdList) ->
             deviceIdList.forEach { deviceId ->
                 cryptoStore.getUserDevice(userId, deviceId)?.let { deviceInfo ->
-                    sendToDeviceMap.setObject(userId, deviceId, messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo)))
+                    sendToDeviceMap.setObject(userId, deviceId, encryptEventContent(payloadJson, listOf(deviceInfo)))
                 }
             }
         }
 
         sendToDevice(EventType.ENCRYPTED, sendToDeviceMap, txnId)
+
+         */
     }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
index 3ab1e0206c..71bbb8e44f 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt
@@ -23,7 +23,6 @@ import org.matrix.android.sdk.api.auth.data.SessionParams
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.internal.crypto.CryptoModule
 import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
-import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
 import org.matrix.android.sdk.internal.di.MatrixComponent
 import org.matrix.android.sdk.internal.federation.FederationModule
 import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker
@@ -132,8 +131,6 @@ internal interface SessionComponent {
 
     fun inject(worker: AddPusherWorker)
 
-    fun inject(worker: UpdateTrustWorker)
-
     @Component.Factory
     interface Factory {
         fun create(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
index 6c68910627..22f0647a28 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt
@@ -40,7 +40,7 @@ import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
 import org.matrix.android.sdk.api.session.room.send.SendState
 import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary
 import org.matrix.android.sdk.api.session.sync.model.RoomSyncUnreadNotifications
-import org.matrix.android.sdk.internal.crypto.EventDecryptor
+import org.matrix.android.sdk.internal.crypto.OlmMachineProvider
 import org.matrix.android.sdk.internal.database.mapper.ContentMapper
 import org.matrix.android.sdk.internal.database.mapper.asDomain
 import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
@@ -72,11 +72,12 @@ internal class RoomSummaryUpdater @Inject constructor(
         @UserId private val userId: String,
         private val roomDisplayNameResolver: RoomDisplayNameResolver,
         private val roomAvatarResolver: RoomAvatarResolver,
-        private val crossSigningService: CrossSigningService,
-        private val eventDecryptor: EventDecryptor,
+        private val olmMachineProvider: OlmMachineProvider,
         private val roomAccountDataDataSource: RoomAccountDataDataSource
 ) {
 
+    private val olmMachine = olmMachineProvider.olmMachine
+
     fun refreshLatestPreviewContent(realm: Realm, roomId: String) {
         val roomSummaryEntity = RoomSummaryEntity.getOrNull(realm, roomId)
         if (roomSummaryEntity != null) {
@@ -194,7 +195,7 @@ internal class RoomSummaryUpdater @Inject constructor(
                 if (root.type == EventType.ENCRYPTED && root.decryptionResultJson == null) {
                     Timber.v("Should decrypt $eventId")
                     tryOrNull {
-                        runBlocking { eventDecryptor.decryptEvent(root.asDomain(), "") }
+                        runBlocking { olmMachine.decryptRoomEvent(root.asDomain()) }
                     }?.let { root.setDecryptionResult(it) }
                 }
             }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt
index 75df8aae1f..36d4aa2bd1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/GetEventTask.kt
@@ -19,8 +19,7 @@ package org.matrix.android.sdk.internal.session.room.timeline
 import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
 import org.matrix.android.sdk.api.session.events.model.Event
-import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
-import org.matrix.android.sdk.internal.crypto.EventDecryptor
+import org.matrix.android.sdk.internal.crypto.DecryptEventUseCase
 import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
 import org.matrix.android.sdk.internal.network.executeRequest
 import org.matrix.android.sdk.internal.session.room.RoomAPI
@@ -38,7 +37,7 @@ internal interface GetEventTask : Task<GetEventTask.Params, Event> {
 internal class DefaultGetEventTask @Inject constructor(
         private val roomAPI: RoomAPI,
         private val globalErrorReceiver: GlobalErrorReceiver,
-        private val cryptoService: DefaultCryptoService,
+        private val decryptEvent: DecryptEventUseCase,
         private val clock: Clock,
 ) : GetEventTask {
 
@@ -50,7 +49,7 @@ internal class DefaultGetEventTask @Inject constructor(
         // Try to decrypt the Event
         if (event.isEncrypted()) {
             tryOrNull(message = "Unable to decrypt the event") {
-                cryptoService.decryptEvent(event, "")
+                decryptEvent(event)
             }
                     ?.let { result ->
                         event.mxDecryptionResult = OlmDecryptionResult(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt
index 8757c20c0a..c5d7598a46 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt
@@ -42,7 +42,7 @@ internal class TimelineEventDecryptor @Inject constructor(
 ) {
 
     private val newSessionListener = object : NewSessionListener {
-        override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
+        override fun onNewSession(roomId: String?, sessionId: String) {
             synchronized(unknownSessionsFailure) {
                 unknownSessionsFailure[sessionId]
                         ?.toList()
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
index f9c2a88daf..4910c74e59 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt
@@ -36,6 +36,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_S
 import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
 import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
+import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
 import org.matrix.android.sdk.api.session.crypto.keysbackup.computeRecoveryKey
 import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
index fc39165a7e..855f5c065e 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt
@@ -90,7 +90,7 @@ class HomeDetailViewModel @AssistedInject constructor(
     }
 
     private val refreshRoomSummariesOnCryptoSessionChange = object : NewSessionListener {
-        override fun onNewSession(roomId: String?, senderKey: String, sessionId: String) {
+        override fun onNewSession(roomId: String?, sessionId: String) {
             session.roomService().refreshJoinedRoomSummaryPreviews(roomId)
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
index d661072d92..39e6e39e14 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt
@@ -72,6 +72,7 @@ import kotlinx.coroutines.launch
 import me.gujun.android.span.span
 import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
 import org.matrix.android.sdk.api.raw.RawService
+import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
 import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
 import javax.inject.Inject
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
index 88e2ed37cf..f335e1d3c8 100644
--- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt
@@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
 import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
 import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage
 import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
 import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth
 import org.matrix.android.sdk.api.util.fromBase64
 import org.matrix.android.sdk.flow.flow
diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt
index 400845284e..02da3ea879 100644
--- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt
+++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutController.kt
@@ -18,6 +18,7 @@ package im.vector.app.features.signout.soft
 
 import com.airbnb.epoxy.EpoxyController
 import com.airbnb.mvrx.Fail
+import com.airbnb.mvrx.Incomplete
 import com.airbnb.mvrx.Loading
 import com.airbnb.mvrx.Success
 import com.airbnb.mvrx.Uninitialized