diff --git a/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt b/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt
index d8f1cf50c6814195edb1e163c1bcb7b0a486998c..9b749b3df705cc6f1d39460d6bb65b9d0dc9f2b9 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/NotifiableEventResolver.kt
@@ -209,8 +209,7 @@ class NotifiableEventResolver @Inject constructor(
                     payload = result.clearEvent,
                     senderKey = result.senderCurve25519Key,
                     keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
-                    forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain,
-                    isSafe = result.isSafe
+                    forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
                 )
             } catch (ignore: MXCryptoError) {
             }
diff --git a/app/src/main/java/org/futo/circles/model/NotificationAction.kt b/app/src/main/java/org/futo/circles/model/NotificationAction.kt
index 43fda9a57df0ae58d3b2b34359b10fa8593e550f..78a9ce7f170172447eb68277dc36f4917e20529a 100644
--- a/app/src/main/java/org/futo/circles/model/NotificationAction.kt
+++ b/app/src/main/java/org/futo/circles/model/NotificationAction.kt
@@ -3,9 +3,9 @@ package org.futo.circles.model
 import org.matrix.android.sdk.api.session.pushrules.Action
 
 data class NotificationAction(
-        val shouldNotify: Boolean,
-        val highlight: Boolean,
-        val soundName: String?
+    val shouldNotify: Boolean,
+    val highlight: Boolean,
+    val soundName: String?
 )
 
 fun List<Action>.toNotificationAction(): NotificationAction {
@@ -15,7 +15,6 @@ fun List<Action>.toNotificationAction(): NotificationAction {
     forEach { action ->
         when (action) {
             is Action.Notify -> shouldNotify = true
-            is Action.DoNotNotify -> shouldNotify = false
             is Action.Highlight -> highlight = action.highlight
             is Action.Sound -> sound = action.sound
         }
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsDataSource.kt
index 7be37c8494da2c3b431ae607b4ab7a6a3ecf73cc..f2ab8ff523d7677734107364ac8b91b53995b9c9 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/ActiveSessionsDataSource.kt
@@ -20,7 +20,6 @@ import org.futo.circles.core.extensions.createResult
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
-import org.matrix.android.sdk.api.util.awaitCallback
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
@@ -94,16 +93,12 @@ class ActiveSessionsDataSource @Inject constructor(
     }
 
     suspend fun removeSession(deviceId: String): Response<Unit> = createResult {
-        awaitCallback {
-            session.cryptoService().deleteDevice(deviceId, authConfirmationProvider, it)
-        }
+        session.cryptoService().deleteDevice(deviceId, authConfirmationProvider)
     }
 
     suspend fun resetKeysToEnableCrossSigning(): Response<Unit> = createResult {
-        awaitCallback {
-            session.cryptoService().crossSigningService()
-                .initializeCrossSigning(authConfirmationProvider, it)
-        }
+        session.cryptoService().crossSigningService()
+            .initializeCrossSigning(authConfirmationProvider)
     }
 
     private fun isSessionInactive(lastSeenTsMillis: Long?): Boolean =
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionDialogFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionDialogFragment.kt
index 0c3bec326cec3dcdb48359d344a955a617f67007..57502b486b05179f63f8c61928e1bbe435d7c2e8 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionDialogFragment.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionDialogFragment.kt
@@ -14,13 +14,13 @@ import org.futo.circles.auth.model.QrCanceled
 import org.futo.circles.auth.model.QrLoading
 import org.futo.circles.auth.model.QrReady
 import org.futo.circles.auth.model.QrSuccess
+import org.futo.circles.core.base.fragment.BaseFullscreenDialogFragment
 import org.futo.circles.core.extensions.gone
 import org.futo.circles.core.extensions.observeData
 import org.futo.circles.core.extensions.onBackPressed
 import org.futo.circles.core.extensions.showError
 import org.futo.circles.core.extensions.showSuccess
 import org.futo.circles.core.extensions.visible
-import org.futo.circles.core.base.fragment.BaseFullscreenDialogFragment
 import org.futo.circles.core.feature.picker.helper.RuntimePermissionHelper
 
 @AndroidEntryPoint
@@ -61,11 +61,11 @@ class VerifySessionDialogFragment :
         viewModel.qrStateLiveData.observeData(this) { qrState ->
             when (qrState) {
                 is QrCanceled -> {
-                    showError(qrState.reason)
+                    showError(getString(R.string.verification_canceled))
                     view?.postDelayed({ onBackPressed() }, CLOSE_DELAY)
                 }
 
-                is QrLoading -> handelQrLoading(qrState.deviceId, qrState.isCurrentSessionVerified)
+                is QrLoading -> handelQrLoading()
                 is QrReady -> handelQrReady(qrState.qrText)
                 is QrSuccess -> {
                     showSuccess(getString(R.string.session_verified))
@@ -85,13 +85,12 @@ class VerifySessionDialogFragment :
         }
     }
 
-    private fun handelQrLoading(deviceId: String, isSessionVerified: Boolean) {
+    private fun handelQrLoading() {
         with(binding) {
             vLoading.visible()
             ivQr.visibility = View.INVISIBLE
             btnVerify.isEnabled = false
-            val sessionName = if (isSessionVerified) deviceId else getString(R.string.cross_signed)
-            tvMessage.text = getString(R.string.waiting_for_verification_format, sessionName)
+            tvMessage.text = getString(R.string.waiting_for_other_device_verification)
         }
     }
 
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionViewModel.kt
index 80785bbd2c77d4d81e4129687d99ce492704d743..69f741c91acbea0856dd637b6062174f60b40f51 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionViewModel.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/active_sessions/verify/VerifySessionViewModel.kt
@@ -3,26 +3,33 @@ package org.futo.circles.auth.feature.active_sessions.verify
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
 import dagger.hilt.android.lifecycle.HiltViewModel
-import org.futo.circles.auth.model.QrCanceled
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.cancellable
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.futo.circles.auth.model.QrLoading
 import org.futo.circles.auth.model.QrReady
 import org.futo.circles.auth.model.QrState
 import org.futo.circles.auth.model.QrSuccess
 import org.futo.circles.core.extensions.getOrThrow
+import org.futo.circles.core.extensions.launchBg
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.matrix.android.sdk.api.session.crypto.verification.EVerificationState
 import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
+import org.matrix.android.sdk.api.session.crypto.verification.QRCodeVerificationState
 import org.matrix.android.sdk.api.session.crypto.verification.QrCodeVerificationTransaction
+import org.matrix.android.sdk.api.session.crypto.verification.VerificationEvent
 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.VerificationTransaction
-import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
 import javax.inject.Inject
 
 @HiltViewModel
 class VerifySessionViewModel @Inject constructor(
     savedStateHandle: SavedStateHandle
-) : ViewModel(), VerificationService.Listener {
+) : ViewModel() {
 
     private val deviceId: String = savedStateHandle.getOrThrow("deviceId")
 
@@ -33,78 +40,74 @@ class VerifySessionViewModel @Inject constructor(
         VerificationMethod.QR_CODE_SCAN
     )
 
-    val qrStateLiveData: MutableLiveData<QrState> = MutableLiveData(
-        QrLoading(
-            deviceId,
-            session.cryptoService().crossSigningService().isCrossSigningVerified()
-        )
-    )
-
-    private var qrTransaction: QrCodeVerificationTransaction? = null
+    val qrStateLiveData: MutableLiveData<QrState> = MutableLiveData(QrLoading)
+    private var qrTransactionId: String = ""
 
     init {
-        session.cryptoService().verificationService().addListener(this)
+        observeVerificationState()
         initVerification()
     }
 
-    override fun verificationRequestCreated(pr: PendingVerificationRequest) {
-        verificationRequestUpdated(pr)
+    private fun observeVerificationState() {
+        session.cryptoService().verificationService().requestEventFlow()
+            .cancellable()
+            .onEach {
+                when (it) {
+                    is VerificationEvent.RequestAdded -> confirmIncomingRequest(it.request)
+
+                    is VerificationEvent.RequestUpdated -> {
+                        if (it.request.state == EVerificationState.Done) {
+                            qrStateLiveData.postValue(QrSuccess)
+                        } else {
+                            qrTransactionId = it.transactionId
+                            it.request.qrCodeText?.let { qrStateLiveData.postValue(QrReady(it)) }
+                        }
+                    }
+
+                    is VerificationEvent.TransactionAdded -> transactionUpdated(it.transaction)
+                    is VerificationEvent.TransactionUpdated -> transactionUpdated(it.transaction)
+                }
+            }.flowOn(Dispatchers.IO).launchIn(viewModelScope)
     }
 
-    override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
-        confirmIncomingRequest()
-    }
 
-    override fun transactionCreated(tx: VerificationTransaction) {
-        transactionUpdated(tx)
-    }
-
-    override fun transactionUpdated(tx: VerificationTransaction) {
-        when (val state = tx.state) {
-            is VerificationTxState.Cancelled -> qrStateLiveData.postValue(QrCanceled(state.cancelCode.humanReadable))
-            VerificationTxState.Verified -> qrStateLiveData.postValue(QrSuccess)
-            VerificationTxState.QrScannedByOther -> qrTransaction?.otherUserScannedMyQrCode()
-            else -> {
-                qrTransaction = tx as? QrCodeVerificationTransaction
-                qrTransaction?.qrCodeText?.let { qrStateLiveData.postValue(QrReady(it)) }
-            }
-        }
-    }
-
-    override fun onCleared() {
-        qrTransaction?.cancel()
-        session.cryptoService().verificationService().removeListener(this)
-        super.onCleared()
+    private fun transactionUpdated(tx: VerificationTransaction) {
+        val transaction = (tx as? QrCodeVerificationTransaction) ?: return
+        if (transaction.state() == QRCodeVerificationState.WaitingForScanConfirmation)
+            launchBg { transaction.otherUserScannedMyQrCode() }
     }
 
     fun onQrScanned(data: String) {
-        qrTransaction?.userHasScannedOtherQrCode(data)
+        launchBg {
+            session.cryptoService().verificationService().reciprocateQRVerification(
+                session.myUserId, qrTransactionId, data
+            )
+        }
     }
 
     private fun initVerification() {
-        if (session.cryptoService().crossSigningService().isCrossSigningVerified())
-            requestKeyVerification()
-        else confirmIncomingRequest()
-    }
-
-    private fun confirmIncomingRequest() {
-        session.cryptoService().verificationService()
-            .getExistingVerificationRequests(session.myUserId)
-            .lastOrNull { it.isIncoming && !it.isReady }?.let {
-                session.cryptoService().verificationService()
-                    .readyPendingVerification(
-                        verificationMethods,
-                        it.otherUserId,
-                        it.transactionId ?: ""
-                    )
+        launchBg {
+            if (session.cryptoService().crossSigningService().isCrossSigningVerified()) {
+                requestKeyVerification()
+            } else {
+                val request = session.cryptoService().verificationService()
+                    .getExistingVerificationRequests(session.myUserId).lastOrNull { it.isIncoming }
+                request?.let { confirmIncomingRequest(it) }
             }
+        }
     }
 
-    private fun requestKeyVerification() {
-        session.cryptoService().verificationService().requestKeyVerification(
+    private fun confirmIncomingRequest(request: PendingVerificationRequest) = launchBg {
+        session.cryptoService().verificationService().readyPendingVerification(
             verificationMethods,
-            session.myUserId,
-            listOf(deviceId)
+            request.otherUserId,
+            request.transactionId
+        )
+    }
+
+    private suspend fun requestKeyVerification() {
+        session.cryptoService().verificationService().requestDeviceVerification(
+            verificationMethods, session.myUserId, deviceId
         )
     }
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/cross_signing/CrossSigningDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/cross_signing/CrossSigningDataSource.kt
index 1b3595b4b04ca43d8b7b98449a46edad7acfa51e..e50349a05b1570b45919ee9efd7d79968e7e441a 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/cross_signing/CrossSigningDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/cross_signing/CrossSigningDataSource.kt
@@ -1,6 +1,7 @@
 package org.futo.circles.auth.feature.cross_signing
 
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.Session
 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
@@ -9,7 +10,6 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
 import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult
 import org.matrix.android.sdk.api.session.securestorage.KeyRef
 import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec
-import org.matrix.android.sdk.api.util.awaitCallback
 import javax.inject.Inject
 
 class CrossSigningDataSource @Inject constructor() {
@@ -20,7 +20,7 @@ class CrossSigningDataSource @Inject constructor() {
         try {
             session.sharedSecretStorageService().getSecret(MASTER_KEY_SSSS_NAME, null, keySpec)
         } catch (ignore: Throwable) {
-            awaitCallback { crossSigningService.initializeCrossSigning(null, it) }
+            tryOrNull { crossSigningService.initializeCrossSigning(null) }
             storeKeys(session, keySpec)
         }
     }
@@ -45,10 +45,9 @@ class CrossSigningDataSource @Inject constructor() {
                 mskPrivateKey, uskPrivateKey, sskPrivateKey
             )
         if (trustResult.isVerified()) {
-            awaitCallback {
-                session.sessionParams.deviceId?.let { deviceId ->
-                    session.cryptoService().crossSigningService().trustDevice(deviceId, it)
-                }
+            tryOrNull {
+                session.cryptoService().crossSigningService()
+                    .trustDevice(session.sessionParams.deviceId)
             }
         }
     }
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/EncryptionAlgorithmHelper.kt b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/EncryptionAlgorithmHelper.kt
index 6b062a6069ab56f8c6959cd34b2a61f016f9597d..aec6820192edc42618f9f54e62a0555e446893c2 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/EncryptionAlgorithmHelper.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/EncryptionAlgorithmHelper.kt
@@ -3,6 +3,7 @@ package org.futo.circles.auth.feature.pass_phrase
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.matrix.android.sdk.api.crypto.BCRYPT_ALGORITHM_BACKUP
 import org.matrix.android.sdk.api.crypto.BSSPEKE_ALGORITHM_BACKUP
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
 import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult
 import org.matrix.android.sdk.api.util.awaitCallback
@@ -21,10 +22,10 @@ class EncryptionAlgorithmHelper @Inject constructor() {
     }
 
     private suspend fun getEncryptionAlgorithm(): String? {
-        val keyVersion = awaitCallback {
+        val keyVersion = tryOrNull {
             MatrixSessionProvider.currentSession?.cryptoService()?.keysBackupService()
-                ?.getCurrentVersion(it)
-        }.toKeysVersionResult()
+                ?.getCurrentVersion()
+        }?.toKeysVersionResult()
 
         return keyVersion?.algorithm
     }
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt
index 145a87cc560062cfb1a744248644eb9b26e854bb..9dc6c754bad907b60df768099265a5be0d9b2405 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/create/CreatePassPhraseDataSource.kt
@@ -8,10 +8,9 @@ import org.futo.circles.auth.feature.cross_signing.CrossSigningDataSource
 import org.futo.circles.auth.feature.pass_phrase.restore.SSSSDataSource
 import org.futo.circles.core.model.LoadingData
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
 import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
-import org.matrix.android.sdk.api.util.awaitCallback
 import java.security.SecureRandom
 import javax.inject.Inject
 
@@ -29,9 +28,8 @@ class CreatePassPhraseDataSource @Inject constructor(
     suspend fun createPassPhraseBackup() {
         loadingLiveData.postValue(LoadingData(messageId = R.string.generating_recovery_key))
         val keyBackupPrivateKey = generateRandomPrivateKey()
-        val backupCreationInfo = awaitCallback {
-            keysBackupService.prepareKeysBackupVersion(keyBackupPrivateKey, it)
-        }
+        val backupCreationInfo =
+            keysBackupService.prepareKeysBackupVersion(keyBackupPrivateKey, null)
         createKeyBackup(backupCreationInfo)
         val keyData = ssssDataSource.storeBsSpekeKeyIntoSSSS(keyBackupPrivateKey)
         crossSigningDataSource.initCrossSigningIfNeed(keyData.keySpec)
@@ -61,21 +59,19 @@ class CreatePassPhraseDataSource @Inject constructor(
         loadingLiveData.postValue(LoadingData(messageId = R.string.creating_backup))
         val versionData = getCurrentBackupVersion()
 
-        if (versionData?.version.isNullOrBlank()) {
-            awaitCallback<KeysVersion> {
-                keysBackupService.createKeysBackupVersion(backupCreationInfo, it)
-            }
-        } else throw Exception(context.getString(R.string.backup_already_exist))
+        if (versionData?.version.isNullOrBlank())
+            keysBackupService.createKeysBackupVersion(backupCreationInfo)
+        else throw Exception(context.getString(R.string.backup_already_exist))
     }
 
     private suspend fun removeCurrentBackupIfExist() {
         loadingLiveData.postValue(LoadingData(messageId = R.string.removing_backup))
         getCurrentBackupVersion()?.version?.let { version ->
-            awaitCallback { keysBackupService.deleteBackup(version, it) }
+            keysBackupService.deleteBackup(version)
         }
     }
 
     private suspend fun getCurrentBackupVersion() =
-        awaitCallback { keysBackupService.getCurrentVersion(it) }.toKeysVersionResult()
+        tryOrNull { keysBackupService.getCurrentVersion() }?.toKeysVersionResult()
 }
 
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/RestoreBackupDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/RestoreBackupDataSource.kt
index 3d153f77e100233ba1f1cb2036769344a04dcd1f..adf0b26c6faedd521171b0e0f1ead3053550859f 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/RestoreBackupDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/RestoreBackupDataSource.kt
@@ -10,12 +10,11 @@ import org.futo.circles.auth.feature.cross_signing.CrossSigningDataSource
 import org.futo.circles.auth.model.KeyData
 import org.futo.circles.core.model.LoadingData
 import org.futo.circles.core.provider.MatrixSessionProvider
+import org.matrix.android.sdk.api.extensions.tryOrNull
 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.BackupRecoveryKey
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
-import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
 import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
-import org.matrix.android.sdk.api.util.awaitCallback
 import javax.inject.Inject
 
 class RestoreBackupDataSource @Inject constructor(
@@ -59,6 +58,17 @@ class RestoreBackupDataSource @Inject constructor(
                         )
                     )
                 }
+
+                is StepProgressListener.Step.DecryptingKey -> {
+                    loadingLiveData.postValue(
+                        LoadingData(
+                            R.string.decrypting_key,
+                            step.progress,
+                            step.total,
+                            true
+                        )
+                    )
+                }
             }
         }
     }
@@ -102,18 +112,15 @@ class RestoreBackupDataSource @Inject constructor(
         val keysBackupService = getKeysBackupService()
         try {
             val keyVersion = getKeysVersion(keysBackupService)
-            awaitCallback {
-                keysBackupService.restoreKeysWithRecoveryKey(
-                    keyVersion,
-                    keyData.recoveryKey,
-                    null,
-                    MatrixSessionProvider.currentSession?.myUserId,
-                    progressObserver,
-                    it
-                )
-            }
+            keysBackupService.restoreKeysWithRecoveryKey(
+                keyVersion,
+                BackupRecoveryKey.fromBase58(keyData.recoveryKey),
+                null,
+                MatrixSessionProvider.currentSession?.myUserId,
+                progressObserver
+            )
             crossSigningDataSource.configureCrossSigning(keyData.keySpec)
-            trustOnDecrypt(keysBackupService, keyVersion)
+            keysBackupService.trustKeysBackupVersion(keyVersion, true)
         } catch (e: Throwable) {
             loadingLiveData.postValue(LoadingData(isLoading = false))
             throw e
@@ -155,21 +162,10 @@ class RestoreBackupDataSource @Inject constructor(
             ?: throw Exception(context.getString(R.string.backup_could_not_be_decrypted_with_key))
     }
 
-    private suspend fun trustOnDecrypt(
-        keysBackup: KeysBackupService,
-        keysVersionResult: KeysVersionResult
-    ) {
-        awaitCallback {
-            keysBackup.trustKeysBackupVersion(keysVersionResult, true, it)
-        }
-    }
-
     private fun getKeysBackupService() =
         MatrixSessionProvider.getSessionOrThrow().cryptoService().keysBackupService()
 
     private suspend fun getKeysVersion(keysBackupService: KeysBackupService) =
-        awaitCallback<KeysBackupLastVersionResult> {
-            keysBackupService.getCurrentVersion(it)
-        }.toKeysVersionResult()
+        tryOrNull { keysBackupService.getCurrentVersion() }?.toKeysVersionResult()
             ?: throw Exception(context.getString(R.string.failed_to_get_restore_keys_version))
 }
\ No newline at end of file
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/SSSSDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/SSSSDataSource.kt
index 3342b4dc3d11e56ab0a348ff4cc717d461196da9..88e9b5630e6ea69a197f7e5f6738897abaabc1b3 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/SSSSDataSource.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/restore/SSSSDataSource.kt
@@ -48,7 +48,7 @@ class SSSSDataSource @Inject constructor() {
 
     suspend fun replaceBsSpeke4SKey() {
         val recoveryKey = MatrixSessionProvider.getSessionOrThrow()
-            .cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()?.recoveryKey
+            .cryptoService().keysBackupService().getKeyBackupRecoveryKeyInfo()?.recoveryKey?.toBase64()
             ?: throw Exception("Recovery Key not found")
         val secret = extractCurveKeyFromRecoveryKey(recoveryKey)
             ?: throw Exception("Can not get secret from recovery key")
diff --git a/auth/src/main/java/org/futo/circles/auth/model/QrState.kt b/auth/src/main/java/org/futo/circles/auth/model/QrState.kt
index cdec7098159458bef621c4140ebe950b8fac0a53..882e78756edb53f623896507b3dfb8c05f63905f 100644
--- a/auth/src/main/java/org/futo/circles/auth/model/QrState.kt
+++ b/auth/src/main/java/org/futo/circles/auth/model/QrState.kt
@@ -2,17 +2,10 @@ package org.futo.circles.auth.model
 
 sealed class QrState
 
-data class QrLoading(
-    val deviceId: String,
-    val isCurrentSessionVerified: Boolean
-) : QrState()
+data object QrLoading : QrState()
 
-data class QrReady(
-    val qrText: String
-) : QrState()
+data class QrReady(val qrText: String) : QrState()
 
-object QrSuccess : QrState()
+data object QrSuccess : QrState()
 
-data class QrCanceled(
-    val reason: String
-) : QrState()
\ No newline at end of file
+data object QrCanceled : QrState()
\ No newline at end of file
diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml
index 6cbca7f00d986569b9932dc58a090485a3a35da9..70e3c137c6332eb0355a8bcd93ba06b8c19fc62d 100644
--- a/auth/src/main/res/values/strings.xml
+++ b/auth/src/main/res/values/strings.xml
@@ -48,6 +48,7 @@
     <string name="computing_recovery_key">Computing recovery key.</string>
     <string name="downloading_keys">Downloading keys.</string>
     <string name="importing_keys">Importing keys.</string>
+    <string name="decrypting_key">Decrypting key.</string>
     <string name="failed_to_get_restore_keys_version">Failed to get latest restore keys version.</string>
     <string name="discard_current_registration_progress">Discard current registration progress?</string>
     <string name="domain">Domain</string>
@@ -110,8 +111,9 @@
     <string name="invalid_auth">Invalid auth</string>
     <string name="scan_with_one_of_devices_message">Scan QR code with one of your devices to finish verification</string>
     <string name="cross_signed">cross signed</string>
-    <string name="waiting_for_verification_format">Waiting for %s to start verification</string>
+    <string name="waiting_for_other_device_verification">Waiting for other device to start verification</string>
     <string name="session_verified">Session verified</string>
+    <string name="verification_canceled">Verification canceled</string>
     <string name="active_login_sessions">Active login sessions</string>
     <string name="login_sessions">Login sessions</string>
     <string name="verify_session">Verify session</string>
diff --git a/core/build.gradle b/core/build.gradle
index e085b93d6d794ab52e6cc97978e9139ee06ba3c0..2ad3137041bfd06ce339c38b95adf9f074c5f327 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -69,7 +69,7 @@ dependencies {
     kapt "com.google.dagger:hilt-compiler:$rootProject.ext.hilt_version"
 
     //Matrix
-    api 'org.matrix.android:matrix-sdk-android:1.5.30.16'
+    api 'org.matrix.android:matrix-sdk-android-rustCrypto:1.5.30.24'
 
     //Retrofit2
     def retrofit_version = '2.9.0'
diff --git a/core/src/main/java/org/futo/circles/core/provider/MatrixSessionProvider.kt b/core/src/main/java/org/futo/circles/core/provider/MatrixSessionProvider.kt
index 05976d0b0f7d58d6493e115cf7f1052768c5999d..775acc48e7a15594fd527f96c8c67070822cf32e 100644
--- a/core/src/main/java/org/futo/circles/core/provider/MatrixSessionProvider.kt
+++ b/core/src/main/java/org/futo/circles/core/provider/MatrixSessionProvider.kt
@@ -16,7 +16,8 @@ object MatrixSessionProvider {
     private var notificationSetupListener: MatrixNotificationSetupListener? = null
     private var onNewAuthLister: (() -> Unit)? = null
 
-    fun getSessionOrThrow() = currentSession ?: throw IllegalArgumentException("Session is not created")
+    fun getSessionOrThrow() =
+        currentSession ?: throw IllegalArgumentException("Session is not created")
 
     fun initSession(
         context: Context,
@@ -98,7 +99,9 @@ object MatrixSessionProvider {
 
     //For Room history share
     private fun enableInviteKeysSharing(session: Session) {
-        val isEnabled = session.cryptoService().isShareKeysOnInviteEnabled()
-        if (!isEnabled) session.cryptoService().enableShareKeyOnInvite(true)
+        tryOrNull {
+            val isEnabled = session.cryptoService().isShareKeysOnInviteEnabled()
+            if (!isEnabled) session.cryptoService().enableShareKeyOnInvite(true)
+        }
     }
 }
\ No newline at end of file