87 lines
3.7 KiB
Swift
87 lines
3.7 KiB
Swift
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)
|
||
}
|
||
}
|
||
}
|