1 // Package bip39 is the official Golang implementation of the BIP39 spec.
3 // The official BIP39 spec can be found at
4 // https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
17 "github.com/johngb/langreg"
18 "golang.org/x/crypto/pbkdf2"
20 "github.com/bytom/vapor/wallet/mnemonic/wordlists"
24 // Some bitwise operands for working with big.Ints
25 last11BitsMask = big.NewInt(2047)
26 rightShift11BitsDivider = big.NewInt(2048)
27 bigOne = big.NewInt(1)
28 bigTwo = big.NewInt(2)
30 // used to isolate the checksum bits from the entropy+checksum byte array
31 wordLengthChecksumMasksMapping = map[int]*big.Int{
38 // used to use only the desired x of 8 available checksum bits.
39 // 256 bit (word length 24) requires all 8 bits of the checksum,
40 // and thus no shifting is needed for it (we would get a divByZero crash if we did)
41 wordLengthChecksumShiftMapping = map[int]*big.Int{
48 // wordList is the set of words to use
49 wordList map[string][]string
53 // ErrInvalidMnemonic is returned when trying to use a malformed mnemonic.
54 ErrInvalidMnemonic = errors.New("Invalid menomic")
56 // ErrEntropyLengthInvalid is returned when trying to use an entropy set with
58 ErrEntropyLengthInvalid = errors.New("Entropy length must be [128, 256] and a multiple of 32")
60 // ErrValidatedSeedLengthMismatch is returned when a validated seed is not the
61 // same size as the given seed. This should never happen is present only as a
63 ErrValidatedSeedLengthMismatch = errors.New("Seed length does not match validated seed length")
65 // ErrChecksumIncorrect is returned when entropy has the incorrect checksum.
66 ErrChecksumIncorrect = errors.New("Checksum incorrect")
68 // ErrLanguageTypeIncorrect is return when find incorrect language type
69 ErrLanguageTypeIncorrect = errors.New("Language Type Incorrect")
71 // ErrLanguageTypeIncorrect is return when find incorrect language type
72 ErrLanguageTypeUnsupported = errors.New("Language Type Unsupported")
76 wordList = map[string][]string{
77 "zh_CN": wordlists.ChineseSimplified,
78 "zh_TW": wordlists.ChineseTraditional,
79 "en": wordlists.English,
80 "it": wordlists.Italian,
81 "ja": wordlists.Japanese,
82 "ko": wordlists.Korean,
83 "es": wordlists.Spanish,
87 // SetWordList sets the list of words to use for mnemonics. Currently the list
88 // that is set is used package-wide.
89 func SetWordMap(language string) (map[string]int, error) {
90 if !isLanguageValid(language) {
91 return nil, ErrLanguageTypeIncorrect
93 words, ok := wordList[language]
95 return nil, ErrLanguageTypeUnsupported
97 wordMap := map[string]int{}
98 for i, v := range words {
104 // SetWordList sets the list of words to use for mnemonics. Currently the list
105 // that is set is used package-wide.
106 func SetWordList(language string) ([]string, error) {
107 if !isLanguageValid(language) {
108 return nil, ErrLanguageTypeIncorrect
110 words, ok := wordList[language]
112 return nil, ErrLanguageTypeUnsupported
118 // NewEntropy will create random entropy bytes
119 // so long as the requested size bitSize is an appropriate size.
121 // bitSize has to be a multiple 32 and be within the inclusive range of {128, 256}
122 func NewEntropy(bitSize int) ([]byte, error) {
123 err := validateEntropyBitSize(bitSize)
128 entropy := make([]byte, bitSize/8)
129 _, err = rand.Read(entropy)
133 // EntropyFromMnemonic takes a mnemonic generated by this library,
134 // and returns the input entropy used to generate the given mnemonic.
135 // An error is returned if the given mnemonic is invalid.
136 func EntropyFromMnemonic(mnemonic string, language string) ([]byte, error) {
137 mnemonicSlice, isValid := splitMnemonicWords(mnemonic)
139 return nil, errors.New("Invalid mnemonic")
141 wordMap, err := SetWordMap(language)
146 for _, v := range mnemonicSlice {
147 index, found := wordMap[v]
149 return nil, fmt.Errorf("word `%v` not found in reverse map", v)
151 var wordBytes [2]byte
152 binary.BigEndian.PutUint16(wordBytes[:], uint16(index))
153 b = b.Mul(b, rightShift11BitsDivider)
154 b = b.Or(b, big.NewInt(0).SetBytes(wordBytes[:]))
157 checksum := big.NewInt(0)
158 checksumMask := wordLengthChecksumMasksMapping[len(mnemonicSlice)]
159 checksum = checksum.And(b, checksumMask)
161 b.Div(b, big.NewInt(0).Add(checksumMask, bigOne))
163 // pad entropy if needed
164 entropy = padByteSlice(entropy, len(mnemonicSlice)/3*4)
166 // generate the checksum once again, mask and ensure it equals the checksum we got from the mneomnic
167 entropyChecksumBytes := computeChecksum(entropy)
168 entropyChecksum := big.NewInt(int64(entropyChecksumBytes[0]))
169 if l := len(mnemonicSlice); l != 24 {
170 checksumShift := wordLengthChecksumShiftMapping[l]
171 entropyChecksum.Div(entropyChecksum, checksumShift)
174 if checksum.Cmp(entropyChecksum) != 0 {
175 return nil, errors.New("mnemonic's entropy doesn't match its checksum")
178 // return (padded) entropy
182 // NewMnemonic will return a string consisting of the mnemonic words for
183 // the given entropy.
184 // If the provide entropy is invalid, an error will be returned.
185 func NewMnemonic(entropy []byte, language string) (string, error) {
186 wordList, err := SetWordList(language)
190 // Compute some lengths for convenience
191 entropyBitLength := len(entropy) * 8
192 checksumBitLength := entropyBitLength / 32
193 sentenceLength := (entropyBitLength + checksumBitLength) / 11
195 err = validateEntropyBitSize(entropyBitLength)
200 // Add checksum to entropy
201 entropy = addChecksum(entropy)
203 // Break entropy up into sentenceLength chunks of 11 bits
204 // For each word AND mask the rightmost 11 bits and find the word at that index
205 // Then bitshift entropy 11 bits right and repeat
206 // Add to the last empty slot so we can work with LSBs instead of MSB
208 // Entropy as an int so we can bitmask without worrying about bytes slices
209 entropyInt := new(big.Int).SetBytes(entropy)
211 // Slice to hold words in
212 words := make([]string, sentenceLength)
214 // Throw away big int for AND masking
215 word := big.NewInt(0)
217 for i := sentenceLength - 1; i >= 0; i-- {
218 // Get 11 right most bits and bitshift 11 to the right for next time
219 word.And(entropyInt, last11BitsMask)
220 entropyInt.Div(entropyInt, rightShift11BitsDivider)
222 // Get the bytes representing the 11 bits as a 2 byte slice
223 wordBytes := padByteSlice(word.Bytes(), 2)
225 // Convert bytes to an index and add that word to the list
226 words[i] = wordList[binary.BigEndian.Uint16(wordBytes)]
229 return strings.Join(words, " "), nil
232 // MnemonicToByteArray takes a mnemonic string and turns it into a byte array
233 // suitable for creating another mnemonic.
234 // An error is returned if the mnemonic is invalid.
235 func MnemonicToByteArray(mnemonic string, language string, raw ...bool) ([]byte, error) {
237 mnemonicSlice = strings.Split(mnemonic, " ")
238 entropyBitSize = len(mnemonicSlice) * 11
239 checksumBitSize = entropyBitSize % 32
240 fullByteSize = (entropyBitSize-checksumBitSize)/8 + 1
241 checksumByteSize = fullByteSize - (fullByteSize % 4)
243 wordMap, err := SetWordMap(language)
247 // Pre validate that the mnemonic is well formed and only contains words that
248 // are present in the word list
249 if !IsMnemonicValid(mnemonic, language) {
250 return nil, ErrInvalidMnemonic
253 // Convert word indices to a `big.Int` representing the entropy
254 checksummedEntropy := big.NewInt(0)
255 modulo := big.NewInt(2048)
256 for _, v := range mnemonicSlice {
257 index := big.NewInt(int64(wordMap[v]))
258 checksummedEntropy.Mul(checksummedEntropy, modulo)
259 checksummedEntropy.Add(checksummedEntropy, index)
262 // Calculate the unchecksummed entropy so we can validate that the checksum is
264 checksumModulo := big.NewInt(0).Exp(bigTwo, big.NewInt(int64(checksumBitSize)), nil)
265 rawEntropy := big.NewInt(0).Div(checksummedEntropy, checksumModulo)
267 // Convert `big.Int`s to byte padded byte slices
268 rawEntropyBytes := padByteSlice(rawEntropy.Bytes(), checksumByteSize)
269 checksummedEntropyBytes := padByteSlice(checksummedEntropy.Bytes(), fullByteSize)
271 // Validate that the checksum is correct
272 newChecksummedEntropyBytes := padByteSlice(addChecksum(rawEntropyBytes), fullByteSize)
273 if !compareByteSlices(checksummedEntropyBytes, newChecksummedEntropyBytes) {
274 return nil, ErrChecksumIncorrect
278 return checksummedEntropyBytes, nil
281 return rawEntropyBytes, nil
283 return checksummedEntropyBytes, nil
286 // NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
287 // An error is returned if the mnemonic is not convertible to a byte array.
288 func NewSeedWithErrorChecking(mnemonic string, password string, language string) ([]byte, error) {
289 _, err := MnemonicToByteArray(mnemonic, language)
293 return NewSeed(mnemonic, password), nil
296 // NewSeed creates a hashed seed output given a provided string and password.
297 // No checking is performed to validate that the string provided is a valid mnemonic.
298 func NewSeed(mnemonic string, password string) []byte {
299 return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
302 func isLanguageValid(language string) bool {
303 if len(language) != 2 && len(language) != 5 {
306 if len(language) == 5 && !langreg.IsValidLangRegCode(language) {
309 if len(language) == 2 && !langreg.IsValidLanguageCode(language) {
315 // IsMnemonicValid attempts to verify that the provided mnemonic is valid.
316 // Validity is determined by both the number of words being appropriate,
317 // and that all the words in the mnemonic are present in the word list.
318 func IsMnemonicValid(mnemonic string, language string) bool {
319 // Create a list of all the words in the mnemonic sentence
320 words := strings.Fields(mnemonic)
323 wordCount := len(words)
325 // The number of words should be 12, 15, 18, 21 or 24
326 if wordCount%3 != 0 || wordCount < 12 || wordCount > 24 {
329 wordMap, err := SetWordMap(language)
333 // Check if all words belong in the wordlist
334 for _, word := range words {
335 if _, ok := wordMap[word]; !ok {
343 // Appends to data the first (len(data) / 32)bits of the result of sha256(data)
344 // Currently only supports data up to 32 bytes
345 func addChecksum(data []byte) []byte {
346 // Get first byte of sha256
347 hash := computeChecksum(data)
348 firstChecksumByte := hash[0]
350 // len() is in bytes so we divide by 4
351 checksumBitLength := uint(len(data) / 4)
353 // For each bit of check sum we want we shift the data one the left
354 // and then set the (new) right most bit equal to checksum bit at that index
355 // staring from the left
356 dataBigInt := new(big.Int).SetBytes(data)
357 for i := uint(0); i < checksumBitLength; i++ {
359 dataBigInt.Mul(dataBigInt, bigTwo)
361 // Set rightmost bit if leftmost checksum bit is set
362 if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
363 dataBigInt.Or(dataBigInt, bigOne)
367 return dataBigInt.Bytes()
370 func computeChecksum(data []byte) []byte {
371 hasher := sha256.New()
373 return hasher.Sum(nil)
376 // validateEntropyBitSize ensures that entropy is the correct size for being a
378 func validateEntropyBitSize(bitSize int) error {
379 if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
380 return ErrEntropyLengthInvalid
385 // padByteSlice returns a byte slice of the given size with contents of the
386 // given slice left padded and any empty spaces filled with 0's.
387 func padByteSlice(slice []byte, length int) []byte {
388 offset := length - len(slice)
392 newSlice := make([]byte, length)
393 copy(newSlice[offset:], slice)
397 // compareByteSlices returns true of the byte slices have equal contents and
398 // returns false otherwise.
399 func compareByteSlices(a, b []byte) bool {
400 if len(a) != len(b) {
411 func splitMnemonicWords(mnemonic string) ([]string, bool) {
412 // Create a list of all the words in the mnemonic sentence
413 words := strings.Fields(mnemonic)
416 numOfWords := len(words)
418 // The number of words should be 12, 15, 18, 21 or 24
419 if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {