import Foundation import CryptoKit /// spec, раздел "Мнемоника и seed → Каноническая wordlist". /// 2048 lowercase ASCII слов, sorted lexicographically. /// Binding fingerprint: SHA-256(canonical_bytes) = /// 2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda enum Wordlist { static let canonical: [String] = { guard let url = Bundle.main.url(forResource: "wordlist", withExtension: "txt"), let raw = try? String(contentsOf: url, encoding: .ascii) else { fatalError("Resources/wordlist.txt отсутствует или повреждён") } let words = raw.split(separator: "\n").map { String($0) } precondition(words.count == 2048, "wordlist должен содержать ровно 2048 слов, получено \(words.count)") return words }() /// Binary search index слова в canonical wordlist. static func index(of word: String) -> UInt16? { var lo = 0 var hi = canonical.count while lo < hi { let mid = (lo + hi) / 2 if canonical[mid] < word { lo = mid + 1 } else if canonical[mid] > word { hi = mid } else { return UInt16(mid) } } return nil } /// Verify binding fingerprint при старте приложения (spec обязательное правило). static func verifyBindingFingerprint() -> Bool { let canonicalBytes = canonical.map { $0 + "\n" }.joined().data(using: .ascii)! let hash = SHA256.hash(data: canonicalBytes) let hex = hash.map { String(format: "%02x", $0) }.joined() return hex == "2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda" } }