github.com/turingchain2020/turingchain@v1.1.21/wallet/bipwallet/go-bip39/bip39.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package bip39 A golang implementation of the BIP0039 spec for mnemonic seeds 6 package bip39 7 8 import ( 9 "crypto/rand" 10 "crypto/sha256" 11 "crypto/sha512" 12 "encoding/binary" 13 "errors" 14 "fmt" 15 "math/big" 16 "strings" 17 18 "golang.org/x/crypto/pbkdf2" 19 ) 20 21 // Some bitwise operands for working with big.Ints 22 var ( 23 Last11BitsMask = big.NewInt(2047) 24 RightShift11BitsDivider = big.NewInt(2048) 25 BigOne = big.NewInt(1) 26 BigTwo = big.NewInt(2) 27 ) 28 29 // NewEntropy 新建 30 func NewEntropy(bitSize int) ([]byte, error) { 31 err := validateEntropyBitSize(bitSize) 32 if err != nil { 33 return nil, err 34 } 35 36 entropy := make([]byte, bitSize/8) 37 _, err = rand.Read(entropy) 38 return entropy, err 39 } 40 41 // NewMnemonic lang=0 english word lang=1 chinese word 42 func NewMnemonic(entropy []byte, lang int32) (string, error) { 43 // Compute some lengths for convenience 44 entropyBitLength := len(entropy) * 8 45 checksumBitLength := entropyBitLength / 32 46 sentenceLength := (entropyBitLength + checksumBitLength) / 11 47 48 err := validateEntropyBitSize(entropyBitLength) 49 if err != nil { 50 return "", err 51 } 52 53 // Add checksum to entropy 54 entropy = addChecksum(entropy) 55 56 // Break entropy up into sentenceLength chunks of 11 bits 57 // For each word AND mask the rightmost 11 bits and find the word at that index 58 // Then bitshift entropy 11 bits right and repeat 59 // Add to the last empty slot so we can work with LSBs instead of MSB 60 61 // Entropy as an int so we can bitmask without worrying about bytes slices 62 entropyInt := new(big.Int).SetBytes(entropy) 63 64 // Slice to hold words in 65 words := make([]string, sentenceLength) 66 67 // Throw away big int for AND masking 68 word := big.NewInt(0) 69 70 for i := sentenceLength - 1; i >= 0; i-- { 71 // Get 11 right most bits and bitshift 11 to the right for next time 72 word.And(entropyInt, Last11BitsMask) 73 entropyInt.Div(entropyInt, RightShift11BitsDivider) 74 75 // Get the bytes representing the 11 bits as a 2 byte slice 76 wordBytes := padByteSlice(word.Bytes(), 2) 77 78 // Convert bytes to an index and add that word to the list 79 if lang == 0 { 80 words[i] = wordList[binary.BigEndian.Uint16(wordBytes)] 81 } else { 82 words[i] = wordListCHN[binary.BigEndian.Uint16(wordBytes)] 83 } 84 85 } 86 87 return strings.Join(words, " "), nil 88 } 89 90 // MnemonicToByteArray 转换 91 func MnemonicToByteArray(mnemonic string) ([]byte, error) { 92 // if IsMnemonicValid(mnemonic) == false { 93 // return nil, fmt.Errorf("Invalid mnemonic") 94 // } 95 mnemonicSlice := strings.Split(mnemonic, " ") 96 //lang=0 english word lang=1 chinese word 97 var lang int32 98 if _, found := reverseWordMap[mnemonicSlice[0]]; !found { 99 lang = 1 100 } 101 102 bitSize := len(mnemonicSlice) * 11 103 err := validateEntropyWithChecksumBitSize(bitSize) 104 if err != nil { 105 return nil, err 106 } 107 checksumSize := bitSize % 32 108 109 b := big.NewInt(0) 110 modulo := big.NewInt(2048) 111 for _, v := range mnemonicSlice { 112 var index int 113 var found bool 114 if lang == 0 { 115 index, found = reverseWordMap[v] 116 if !found { 117 return nil, fmt.Errorf("Word `%v` not found in reverse map", v) 118 } 119 } else { 120 index, found = reverseWordMapCHN[v] 121 if !found { 122 return nil, fmt.Errorf("Word `%v` not found in reverse map", v) 123 } 124 } 125 126 add := big.NewInt(int64(index)) 127 b = b.Mul(b, modulo) 128 b = b.Add(b, add) 129 } 130 hex := b.Bytes() 131 checksumModulo := big.NewInt(0).Exp(big.NewInt(2), big.NewInt(int64(checksumSize)), nil) 132 entropy, _ := big.NewInt(0).DivMod(b, checksumModulo, big.NewInt(0)) 133 134 entropyHex := entropy.Bytes() 135 136 byteSize := bitSize/8 + 1 137 if len(hex) != byteSize { 138 tmp := make([]byte, byteSize) 139 diff := byteSize - len(hex) 140 for i := 0; i < len(hex); i++ { 141 tmp[i+diff] = hex[i] 142 } 143 hex = tmp 144 } 145 146 otherSize := byteSize - (byteSize % 4) 147 entropyHex = padHexToSize(entropyHex, otherSize) 148 149 validationHex := addChecksum(entropyHex) 150 validationHex = padHexToSize(validationHex, byteSize) 151 152 if len(hex) != len(validationHex) { 153 panic("[]byte len mismatch - it shouldn't happen") 154 } 155 for i := range validationHex { 156 if hex[i] != validationHex[i] { 157 return nil, fmt.Errorf("Mnemonic checksum error. Check words are in correct order. (decoded byte %v)", i) 158 } 159 } 160 return hex, nil 161 } 162 163 func padHexToSize(hex []byte, size int) []byte { 164 if len(hex) != size { 165 tmp2 := make([]byte, size) 166 diff2 := size - len(hex) 167 for i := 0; i < len(hex); i++ { 168 tmp2[i+diff2] = hex[i] 169 } 170 hex = tmp2 171 } 172 return hex 173 } 174 175 // NewSeedWithErrorChecking 带有错误检查的创建Seed 176 func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) { 177 _, err := MnemonicToByteArray(mnemonic) 178 if err != nil { 179 return nil, err 180 } 181 return NewSeed(mnemonic, password), nil 182 } 183 184 // NewSeed 新建Seed 185 func NewSeed(mnemonic string, password string) []byte { 186 return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New) 187 } 188 189 // Appends to data the first (len(data) / 32)bits of the result of sha256(data) 190 // Currently only supports data up to 32 bytes 191 func addChecksum(data []byte) []byte { 192 // Get first byte of sha256 193 hasher := sha256.New() 194 _, err := hasher.Write(data) 195 if err != nil { 196 return nil 197 } 198 hash := hasher.Sum(nil) 199 firstChecksumByte := hash[0] 200 201 // len() is in bytes so we divide by 4 202 checksumBitLength := uint(len(data) / 4) 203 204 // For each bit of check sum we want we shift the data one the left 205 // and then set the (new) right most bit equal to checksum bit at that index 206 // staring from the left 207 dataBigInt := new(big.Int).SetBytes(data) 208 for i := uint(0); i < checksumBitLength; i++ { 209 // Bitshift 1 left 210 dataBigInt.Mul(dataBigInt, BigTwo) 211 212 // Set rightmost bit if leftmost checksum bit is set 213 if firstChecksumByte&(1<<(7-i)) > 0 { 214 dataBigInt.Or(dataBigInt, BigOne) 215 } 216 } 217 218 return dataBigInt.Bytes() 219 } 220 221 func padByteSlice(slice []byte, length int) []byte { 222 newSlice := make([]byte, length-len(slice)) 223 return append(newSlice, slice...) 224 } 225 226 func validateEntropyBitSize(bitSize int) error { 227 if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 { 228 return errors.New("Entropy length must be [128, 256] and a multiple of 32") 229 } 230 return nil 231 } 232 233 func validateEntropyWithChecksumBitSize(bitSize int) error { 234 if (bitSize != 128+4) && (bitSize != 160+5) && (bitSize != 192+6) && (bitSize != 224+7) && (bitSize != 256+8) { 235 return fmt.Errorf("Wrong entropy + checksum size - expected %v, got %v", (bitSize-bitSize%32)+(bitSize-bitSize%32)/32, bitSize) 236 } 237 return nil 238 } 239 240 // IsMnemonicValid 检测有效性 241 func IsMnemonicValid(mnemonic string) bool { 242 // Create a list of all the words in the mnemonic sentence 243 words := strings.Fields(mnemonic) 244 245 //Get num of words 246 numOfWords := len(words) 247 248 // The number of words should be 12, 15, 18, 21 or 24 249 if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 { 250 return false 251 } 252 253 // Check if all words belong in the wordlist 254 for i := 0; i < numOfWords; i++ { 255 if !contains(wordList, words[i]) { 256 return false 257 } 258 } 259 260 return true 261 } 262 263 func contains(s []string, e string) bool { 264 for _, a := range s { 265 if a == e { 266 return true 267 } 268 } 269 return false 270 }