HD wallet具有管理多個密鑰和地址的機(jī)制循集,我們可以使用一個隨機(jī)字符串seed通過BIP32或BIP44協(xié)議創(chuàng)建一個HD wallet窄刘,但是一串字符串的記憶成本太高睡扬,而且摘抄下來也會很麻煩煌集。所以BIP39協(xié)議應(yīng)運(yùn)而生封字,他是可以使用12-24單字(可以是英文逞怨、中文者疤、日文等等語言)來幫助用戶更好的保存seed。一般我們使用長度為12個的英文單詞來生成BIP39的內(nèi)容叠赦,這串單詞被稱為mnemonic code驹马,中文名叫助記詞。
BIP-39 生成助記詞流程
助記詞錢包是通過BIP-39中定義的標(biāo)準(zhǔn)化過程自動生成的除秀,錢包從熵源開始糯累,增加校驗(yàn)和,然后將熵映射到字典列表中鳞仙。
1.創(chuàng)建一個128-256位的隨機(jī)序列(熵)
2.提出SHA256哈希的前幾位(熵長/32),就可以創(chuàng)建一個隨機(jī)序列的校驗(yàn)和寇蚊。
3.將校驗(yàn)和添加到隨機(jī)序列的末尾。
4.將序列劃分為包含11位的不同部分棍好。
5.將每個包含11位部分的值與一個預(yù)先定義的2048個單詞的字典做對應(yīng)仗岸。
6.生成的有順序的單詞組就是助記詞允耿。
新建項目
導(dǎo)入CryptoSwift
庫
- 新建
BIP39.swift
文件
import Foundation
import CryptoSwift
public enum BIP39Language {
case english
case chinese_simplified
case chinese_traditional
case japanese
case korean
case french
case italian
case spanish
var words: [String] {
switch self {
case .english:
return englishWords
case .chinese_simplified:
return simplifiedchineseWords
case .chinese_traditional:
return traditionalchineseWords
case .japanese:
return japaneseWords
case .korean:
return koreanWords
case.french:
return frenchWords
case .italian:
return italianWords
case .spanish:
return spanishWords
}
}
var separator: String {
switch self {
case .japanese:
return "\u{3000}"
default:
return " "
}
}
}
public class BIP39 {
/// 返回一組助記詞
static public func generateMnemonics(bitsOfEntropy: Int, language: BIP39Language = BIP39Language.english) throws -> String? {
// 1.創(chuàng)建一個128-256位的隨機(jī)序列(熵)
guard bitsOfEntropy >= 128 && bitsOfEntropy <= 256 && bitsOfEntropy % 32 == 0 else {return nil}
guard let entropy = Data.randomBytes(length: bitsOfEntropy/8) else {throw AbstractError.noEntropyError}
return BIP39.generateMnemonicsFromEntropy(entropy: entropy, language: language)
}
/// 通過熵生成助記詞
static public func generateMnemonicsFromEntropy(entropy: Data, language: BIP39Language = BIP39Language.english) -> String? {
guard entropy.count >= 16, entropy.count & 4 == 0 else {return nil}
// 2.提出SHA256哈希的前幾位(熵長/32),就可以創(chuàng)建一個隨機(jī)序列的校驗(yàn)和。
let checksum = entropy.sha256()
// 3.將校驗(yàn)和添加到隨機(jī)序列的末尾扒怖。
let checksumBits = entropy.count*8/32
var fullEntropy = Data()
fullEntropy.append(entropy)
fullEntropy.append(checksum[0 ..< (checksumBits+7)/8 ])
var wordList = [String]()
// 4.將序列劃分為包含11位的不同部分
for i in 0 ..< fullEntropy.count*8/11 {
guard let bits = fullEntropy.bitsInRange(i*11, 11) else {return nil}
let index = Int(bits)
guard language.words.count > index else {return nil}
// 5.將每個包含11位部分的值與一個預(yù)先定義的2048個單詞的字典做對應(yīng)较锡。
let word = language.words[index]
wordList.append(word)
}
let separator = language.separator
// 6.生成的有順序的單詞組就是助記詞。
return wordList.joined(separator: separator)
}
/// 通過助記詞返回一個熵
static public func mnemonicsToEntropy(_ mnemonics: String, language: BIP39Language = BIP39Language.english) -> Data? {
let wordList = mnemonics.components(separatedBy: " ")
guard wordList.count >= 12 && wordList.count % 4 == 0 else {return nil}
var bitString = ""
for word in wordList {
let idx = language.words.index(of: word)
if (idx == nil) {
return nil
}
let idxAsInt = language.words.startIndex.distance(to: idx!)
let stringForm = String(UInt16(idxAsInt), radix: 2).leftPadding(toLength: 11, withPad: "0")
bitString.append(stringForm)
}
let stringCount = bitString.count
if stringCount % 33 != 0 {
return nil
}
let entropyBits = bitString[0 ..< (bitString.count - bitString.count/33)]
let checksumBits = bitString[(bitString.count - bitString.count/33) ..< bitString.count]
guard let entropy = entropyBits.interpretAsBinaryData() else {
return nil
}
let checksum = String(entropy.sha256().bitsInRange(0, checksumBits.count)!, radix: 2).leftPadding(toLength: checksumBits.count, withPad: "0")
if checksum != checksumBits {
return nil
}
return entropy
}
/// 通過助記詞返回一個seed(種子)
static public func seedFromMmemonics(_ mnemonics: String, password: String = "", language: BIP39Language = BIP39Language.english) -> Data? {
let valid = BIP39.mnemonicsToEntropy(mnemonics, language: language) != nil
if (!valid) {
print("Potentially invalid mnemonics")
}
guard let mnemData = mnemonics.decomposedStringWithCompatibilityMapping.data(using: .utf8) else {return nil}
let salt = "mnemonic" + password
guard let saltData = salt.decomposedStringWithCompatibilityMapping.data(using: .utf8) else {return nil}
guard let seedArray = try? PKCS5.PBKDF2(password: mnemData.bytes, salt: saltData.bytes, iterations: 2048, keyLength: 64, variant: HMAC.Variant.sha512).calculate() else {return nil}
let seed = Data(bytes:seedArray)
return seed
}
}
- 統(tǒng)一錯誤處理類
AbstractError.swift
import Foundation
public enum AbstractError: Error {
case noEntropyError
case keyDerivationError
case aesError
case invalidAccountError
case invalidPasswordError
case encryptionError(String)
}
項目結(jié)構(gòu)
image.png
demo使用:
// 生成助記詞
let mnemonic = try! BIP39.generateMnemonics(bitsOfEntropy: 128)!
// 種子
let seed = BIP39.seedFromMmemonics(mnemonic)
print("助記詞:\(mnemonic)")
print("種子seed:\(seed?.toHexString() ?? "")")
示例結(jié)果
助記詞:soldier stay tackle return tackle lens praise leader traffic sword anxiety intact
種子seed:bc428e06a1bc08b3bf52ce6b1fd1a295518888b1de10eea3231043bed07e4ccd108e5a192bfd073d3db81dba8311ed2b109fbda3d6daa63d27000e395a46f887
驗(yàn)證地址:
https://iancoleman.io/bip39/
demo下載地址:
暫未上傳