import XCTest @testable import MontanaApp final class MnemonicTests: XCTestCase { /// spec, раздел "Test vectors (binding) → M-1 Vector 1" /// entropy = [0x00; 32] /// mnemonic = "abandon abandon ... abandon art" /// master_seed = 38a1421ac3ce191fbdc46b1cca266a9d72d22320fb38bda6a3df90a1ead664a7 /// 8951703197be882ace38e0f557a492a8e9ff5e3c02290a8eecf5939468708edb func testM1Vector1_ZeroEntropy() throws { let entropy = Data(count: 32) let mnemonic = try Mnemonic.encode(entropy: entropy) XCTAssertEqual(mnemonic.split(whereSeparator: { $0.isWhitespace }).count, 24) XCTAssertTrue(mnemonic.hasSuffix(" art"), "BIP-39 standard: zero entropy + checksum 0x66 → word 'art'") let masterSeed = try Mnemonic.decodeAndDerive(mnemonic: mnemonic) let hex = masterSeed.map { String(format: "%02x", $0) }.joined() XCTAssertEqual(hex, "38a1421ac3ce191fbdc46b1cca266a9d72d22320fb38bda6a3df90a1ead664a7" + "8951703197be882ace38e0f557a492a8e9ff5e3c02290a8eecf5939468708edb" ) } /// spec, раздел "Test vectors (binding) → M-1 Vector 2" /// entropy = [0xFF; 32] /// master_seed = a5925c51583447a0abe43b65dbc591f3780a91c7d44c6b333975a211096039f3 /// d1d0ca9e125aa4e756f0a35b0006378ac69450e8254e32f16409a350f3ca9104 func testM1Vector2_MaxEntropy() throws { let entropy = Data(repeating: 0xFF, count: 32) let mnemonic = try Mnemonic.encode(entropy: entropy) XCTAssertTrue(mnemonic.hasSuffix(" vote")) let masterSeed = try Mnemonic.decodeAndDerive(mnemonic: mnemonic) let hex = masterSeed.map { String(format: "%02x", $0) }.joined() XCTAssertEqual(hex, "a5925c51583447a0abe43b65dbc591f3780a91c7d44c6b333975a211096039f3" + "d1d0ca9e125aa4e756f0a35b0006378ac69450e8254e32f16409a350f3ca9104" ) } func testWordlistFingerprint() { XCTAssertTrue(Wordlist.verifyBindingFingerprint(), "wordlist.txt SHA-256 должен соответствовать spec binding fingerprint") } func testGenerateProduces24Words() { let m = Mnemonic.generate() XCTAssertEqual(m.split(whereSeparator: { $0.isWhitespace }).count, 24) } func testRoundtrip() throws { let entropy = Data((0..<32).map { _ in UInt8.random(in: 0...255) }) let mnemonic = try Mnemonic.encode(entropy: entropy) let seed1 = try Mnemonic.decodeAndDerive(mnemonic: mnemonic) let seed2 = try Mnemonic.decodeAndDerive(mnemonic: mnemonic) XCTAssertEqual(seed1, seed2, "Determinism") } func testInvalidWordCount() { XCTAssertThrowsError(try Mnemonic.decodeAndDerive(mnemonic: "abandon abandon")) { err in if case Mnemonic.MnemonicError.wordCount(let n) = err { XCTAssertEqual(n, 2) } else { XCTFail("expected wordCount error") } } } func testInvalidWord() { let bad = Array(repeating: "abandon", count: 23).joined(separator: " ") + " bogusword" XCTAssertThrowsError(try Mnemonic.decodeAndDerive(mnemonic: bad)) { err in if case Mnemonic.MnemonicError.unknownWord(let pos) = err { XCTAssertEqual(pos, 23) } else { XCTFail("expected unknownWord error") } } } func testInvalidChecksum() { let m = Array(repeating: "abandon", count: 24).joined(separator: " ") XCTAssertThrowsError(try Mnemonic.decodeAndDerive(mnemonic: m)) { err in XCTAssertEqual(err as? Mnemonic.MnemonicError, .checksumMismatch) } } }