Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: BIP39 use given language to generate mnemonics; #852

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Sources/Web3Core/KeystoreManager/BIP39.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import Foundation
import CryptoSwift

public enum BIP39Language {
public enum BIP39Language: CaseIterable {
case english
case chinese_simplified
case chinese_traditional
Expand Down Expand Up @@ -36,7 +36,12 @@ public enum BIP39Language {
return spanishWords
}
}

public var separator: String {
return String(separatorCharacter)
}

public var separatorCharacter: Character {
switch self {
case .japanese:
return "\u{3000}"
Expand Down Expand Up @@ -124,7 +129,7 @@ public class BIP39 {
public static func generateMnemonicsFromEntropy(entropy: Data, language: BIP39Language = .english) -> String? {
guard entropy.count >= 16, entropy.count & 4 == 0 else { return nil }
let separator = language.separator
let wordList = generateMnemonicsFrom(entropy: entropy)
let wordList = generateMnemonicsFrom(entropy: entropy, language: language)
return wordList.joined(separator: separator)
}

Expand Down
30 changes: 30 additions & 0 deletions Tests/web3swiftTests/localTests/BIP39Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ final class BIP39Tests: XCTestCase {
XCTAssert(keystore1?.addresses?.first == keystore2?.addresses?.first)
}

/// It's expected for the entropy bits count to be [128, 256] and (bits mod 32) must return 0.
func testWrongBitsOfEntropyMustThrow() throws {
XCTAssertThrowsError(try BIP39.generateMnemonics(entropy: 127))
XCTAssertThrowsError(try BIP39.generateMnemonics(entropy: 255))
Expand All @@ -166,4 +167,33 @@ final class BIP39Tests: XCTestCase {
XCTAssertFalse(try BIP39.generateMnemonics(entropy: 256).isEmpty)
}

func testBip39CorrectWordsCount() throws {
XCTAssertEqual(try BIP39.generateMnemonics(entropy: 128).count, 12)
XCTAssertEqual(try BIP39.generateMnemonics(entropy: 160).count, 15)
XCTAssertEqual(try BIP39.generateMnemonics(entropy: 192).count, 18)
XCTAssertEqual(try BIP39.generateMnemonics(entropy: 224).count, 21)
XCTAssertEqual(try BIP39.generateMnemonics(entropy: 256).count, 24)
}

func testAllLanguageMnemonics() throws {
for language in BIP39Language.allCases {
let mnemonicPhrase = try BIP39.generateMnemonics(entropy: 128, language: language)
for word in mnemonicPhrase {
guard language.words.contains(word) else {
XCTFail("Given word is not contained in the list of words of selected language available for mnemonics generation: \(word); \(language)")
return
}
}
}
}

func testBip39MnemonicSeparatorUse() throws {
for language in BIP39Language.allCases {
guard let mnemonicPhrase = try BIP39.generateMnemonics(bitsOfEntropy: 128, language: language) else {
XCTFail("Failed to generate BIP39 mnemonics phrase with 128 bits of entropy using language: \(language)")
return
}
XCTAssertEqual(mnemonicPhrase.split(whereSeparator: { $0 == language.separatorCharacter }).count, 12)
}
}
}
Loading