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  }