import Foundation import SwiftUI /// Минимальный держатель identity для первой итерации. /// Полные derived keys (ML-DSA + ML-KEM) — Phase 2 (FFI к Rust). struct Identity: Equatable { let masterSeed: Data let accountIdHex: String let mnemonic: String? } @MainActor final class IdentityManager: ObservableObject { @Published private(set) var identity: Identity? private let storageKey = "MontanaIdentity_v1" init() {} /// Загрузить existing identity из Keychain (если есть). func loadIfPresent() { guard let data = KeychainStore.read(key: storageKey), let stored = try? JSONDecoder().decode(StoredIdentity.self, from: data) else { return } identity = Identity( masterSeed: stored.masterSeed, accountIdHex: stored.accountIdHex, mnemonic: nil ) } /// Создать новую identity из случайной мнемоники. func createNew() throws -> String { let mnemonic = Mnemonic.generate() try install(mnemonic: mnemonic) return mnemonic } /// Восстановить identity из существующей мнемоники. func restore(from mnemonic: String) throws { try install(mnemonic: mnemonic) } /// Стереть identity локально (для тестов / переустановки). func wipe() { KeychainStore.delete(key: storageKey) identity = nil } private func install(mnemonic: String) throws { let masterSeed = try Mnemonic.decodeAndDerive(mnemonic: mnemonic) // Placeholder account_id = SHA-256("mt-account-placeholder" || masterSeed[0..16]) // Реальный account_id = SHA-256("mt-account" || pubkey_suite || ml_dsa_pubkey) — Phase 2 let accountIdHex = HashUtil.sha256Hex(prefix: "mt-account-placeholder", body: masterSeed.prefix(16)) let stored = StoredIdentity(masterSeed: masterSeed, accountIdHex: accountIdHex) let data = try JSONEncoder().encode(stored) KeychainStore.write(key: storageKey, value: data) identity = Identity(masterSeed: masterSeed, accountIdHex: accountIdHex, mnemonic: mnemonic) } } private struct StoredIdentity: Codable { let masterSeed: Data let accountIdHex: String }