
니모닉(Mnemonic)이란 결정적 지갑에서 난수 12개의 영단어로 인코딩한 영단어 그룹으로, BIP-39에서 제안되었습니다.
암호화폐 지갑은 비대칭키 암호 방식을 사용합니다. 이때 공개키와 개인키(=비밀키)가 사용이 되는데, 이 개인키를 사람이 쓰기 편하게 만들어진 것이 바로, 니모닉(mnemonic)입니다.
키 스트레칭 함수 PBKDF2() 함수에 니모닉 코드 단어 + Salt를 넣는다.


Go-ethereum 계정을 구현하는 패키지이다.
https://github.com/miguelmota/go-ethereum-hdwallet
go get github.com/miguelmota/go-ethereum-hdwallet// TODO : mnemonic 패키지의 함수를 사용하여 랜덤한 니모닉 코드를 얻습니다.
func NewMnemonic(c *gin.Context) {
	// entropy 변수에는 hdwallet.NewEntropy 의 결과값을 받습니다.
	// 256 비트의 엔트로피를 생성합니다.
	entropy, err := hdwallet.NewEntropy(256)
	utils.ErrorHandler(err, c, http.StatusServiceUnavailable)
	// mnemonic 변수에는 hdwallet.NewMnemonicFromEntropy 의 결과값을 받습니다.
	// entropy를 인자값으로 줍니다.
	mnemonic, err := hdwallet.NewMnemonicFromEntropy(entropy)
	utils.ErrorHandler(err, c, http.StatusServiceUnavailable)
	// mnemonic 응답 값을 담을 model 구조체를 만듭니다.
	// (응답) model 구조체 변수에 mnemonic을 담아 응답으로 전송합니다.
	c.IndentedJSON(http.StatusOK, model.MnemonicResponse{Mnemonic: mnemonic})
}func NewEntropy(bits int) ([]byte, error) {
	return bip39.NewEntropy(bits)
}func NewMnemonicFromEntropy(entropy []byte) (string, error) {
	return bip39.NewMnemonic(entropy)
}// TODO : 니모닉 코드를 이용해 private key, address를 생성합니다.
func NewWallet(c *gin.Context) {
	// 요청에 포함되어 있는 mnemonic을 파싱합니다.
	var body model.WalletCreateRequest
	if err := c.ShouldBindJSON(&body); err != nil {
		utils.ErrorHandler(err, c, http.StatusBadRequest)
	}
	//mnemonic 변수에는 body 값에서 파싱한 mnemonic 값을 받습니다.
	mnemonic := body.Mnemonic
	// seed 변수에는 hdwallet.NewSeedFromMnemonic 의 결과값을 받습니다.
	// mnemonic 값을 인자값으로 줍니다.
	seed, err := hdwallet.NewSeedFromMnemonic(mnemonic)
	utils.ErrorHandler(err, c, http.StatusServiceUnavailable)
	// wallet 변수에는 hdwallet.NewFromSeed 의 결과값을 받습니다.
	// seed 값을 인자값으로 줍니다.
	wallet, err := hdwallet.NewFromSeed(seed)
	utils.ErrorHandler(err, c, http.StatusServiceUnavailable)
	// path 변수에는 hdwallet.MustParseDerivationPath 의 결과값을 받습니다.
	// bip44 경로를 인자값으로 줍니다.
	path := hdwallet.MustParseDerivationPath("m/44'/60'/0'/0/0")
	// account 변수에는 *wallet.Derive 의 결과값을 받습니다.
	// path 값을 인자값으로 줍니다.
	account, err := wallet.Derive(path, false)
	utils.ErrorHandler(err, c, http.StatusServiceUnavailable)
	// privateKey 변수에는 *wallet.PrivateKeyHex 의 결과값을 받습니다.
	// account 값을 인자값으로 줍니다.
	privateKey, _ := wallet.PrivateKeyHex(account)
	// address 변수에는 account.Address 의 결과값을 받습니다.
	address := account.Address.Hex()
	// privateKey, address 응답 값을 담을 model 구조체를 만듭니다.
	var result model.WalletResponse
	// (응답) model 구조체 변수에 privateKey, address 값을 담아 응답으로 전송합니다.
	result.PrivateKey = privateKey
	result.Address = address
	c.IndentedJSON(http.StatusOK, result)
}func NewSeedFromMnemonic(mnemonic string) ([]byte, error) {
	if mnemonic == "" {
		return nil, errors.New("mnemonic is required")
	}
	return bip39.NewSeedWithErrorChecking(mnemonic, "")
}func NewFromSeed(seed []byte) (*Wallet, error) {
	if len(seed) == 0 {
		return nil, errors.New("seed is required")
	}
	return newWallet(seed)
}m/44'/60'/0'/0/0
m / purpose' / coin_type' / account' / change / address_indexpurpose : 항상 44
coin_type : 코인 종류(암호화폐의 유형)
account : 계정
change : 잔돈 계정 여부
address_index : 사용 가능한 주소 인덱스
func MustParseDerivationPath(path string) accounts.DerivationPath {
	parsed, err := accounts.ParseDerivationPath(path)
	if err != nil {
		panic(err)
	}
	return parsed
}pin을 true로 설정하면 계정이 목록에 추가됩니다.
func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
	// Try to derive the actual account and update its URL if successful
	w.stateLock.RLock() // Avoid device disappearing during derivation
	address, err := w.deriveAddress(path)
	w.stateLock.RUnlock()
	// If an error occurred or no pinning was requested, return
	if err != nil {
		return accounts.Account{}, err
	}func (w *Wallet) PrivateKeyHex(account accounts.Account) (string, error) {
	privateKeyBytes, err := w.PrivateKeyBytes(account)
	if err != nil {
		return "", err
	}
	return hexutil.Encode(privateKeyBytes)[2:], nil
}func (a Address) Hex() string {
	return string(a.checksumHex())
}