Skip to content

Commit

Permalink
add checksum validity check to Mnemonic isValid func
Browse files Browse the repository at this point in the history
  • Loading branch information
simonmcl committed Sep 25, 2023
1 parent d519571 commit 7a4019c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
38 changes: 37 additions & 1 deletion Sources/KukaiCryptoSwift/Mnemonic/Mnemonic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import Foundation
import CommonCrypto
import CryptoKit

public enum MnemonicError: Swift.Error {
case seedDerivationFailed
Expand Down Expand Up @@ -122,6 +123,41 @@ public struct Mnemonic: Equatable, Codable {
phrase = String(repeating: "0", count: phrase.count)
}

/**
Derive the checksum portion of an array of bits
*/
public static func deriveChecksumBits(_ bytes: [UInt8]) -> String {
let ENT = bytes.count * 8;
let CS = ENT / 32

let hash = SHA256.hash(data: bytes)
let hashbits = String(hash.flatMap { ("00000000" + String($0, radix:2)).suffix(8) })
return String(hashbits.prefix(CS))
}

/**
Verify the chechsum of the supplied words to esnure its a valid phrase
*/
public static func isValidChecksum(phrase: [String], wordlist: WordList = WordList.english) -> Bool {
let wordL = wordlist.words
var bits = ""
for word in phrase {
guard let i = wordL.firstIndex(of: word) else { return false }
bits += ("00000000000" + String(i, radix: 2)).suffix(11)
}

let dividerIndex = bits.count / 33 * 32
let entropyBits = String(bits.prefix(dividerIndex))
let checksumBits = String(bits.suffix(bits.count - dividerIndex))

let regex = try! NSRegularExpression(pattern: "[01]{1,8}", options: .caseInsensitive)
let entropyBytes = regex.matches(in: entropyBits, options: [], range: NSRange(location: 0, length: entropyBits.count)).map {
UInt8(strtoul(String(entropyBits[Range($0.range, in: entropyBits)!]), nil, 2))
}

return checksumBits == deriveChecksumBits(entropyBytes)
}

/**
Check a mnemonic is of the correct length, and is made up of valid BIP39 words
*/
Expand All @@ -140,6 +176,6 @@ public struct Mnemonic: Equatable, Codable {
}
}

return true
return Mnemonic.isValidChecksum(phrase: words, wordlist: vocabulary)
}
}
5 changes: 4 additions & 1 deletion Tests/KukaiCryptoSwiftTests/MnemonicTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,15 @@ final class MnemonicTests: XCTestCase {
XCTAssert(mnemonic3.isValid() == false)

let mnemonic4 = try Mnemonic(seedPhrase: "remember smile trip tumble era cube worry fuel bracket eight kitten inform remember smile trip tumble era cube worry fuel bracket eight kitten inform")
XCTAssert(mnemonic4.isValid() == true)
XCTAssert(mnemonic4.isValid() == false)

let mnemonic5 = try Mnemonic(seedPhrase: "remember smile trip tumble era cube worry fuel bracket eight kitten inform remember smile trip tumble era cube worry fuel bracket eight kitten infomr")
XCTAssert(mnemonic5.isValid() == false)

let mnemonic6 = try Mnemonic(seedPhrase: "tell me more about your awesome but totally invalid mnemonic word1 word2")
XCTAssert(mnemonic6.isValid() == false)

let mnemonic7 = try Mnemonic(seedPhrase: "remember smile trip tumble era cube worry fuel bracket eight kitten remember")
XCTAssert(mnemonic7.isValid() == false)
}
}

0 comments on commit 7a4019c

Please sign in to comment.