func New(dir string, desc string, passphrase []byte, net *chaincfg.Params,
	createdAt *BlockStamp) (*Store, error) {
	if len(desc) > 256 {
		return nil, errors.New("desc exceeds 256 byte maximum size")
	}
	rootkey := make([]byte, 32)
	if _, err := rand.Read(rootkey); err != nil {
		return nil, err
	}
	chaincode := make([]byte, 32)
	if _, err := rand.Read(chaincode); err != nil {
		return nil, err
	}
	kdfp, err := computeKdfParameters(defaultKdfComputeTime, defaultKdfMaxMem)
	if err != nil {
		return nil, err
	}
	aeskey := kdf(passphrase, kdfp)
	s := &Store{
		path: filepath.Join(dir, Filename),
		dir:  dir,
		file: Filename,
		vers: VersCurrent,
		net:  (*netParams)(net),
		flags: walletFlags{
			useEncryption: true,
			watchingOnly:  false,
		},
		createDate:  time.Now().Unix(),
		highestUsed: rootKeyChainIdx,
		kdfParams:   *kdfp,
		recent: recentBlocks{
			lastHeight: createdAt.Height,
			hashes: []*chainhash.Hash{
				createdAt.Hash,
			},
		},
		addrMap:          make(map[addressKey]walletAddress),
		chainIdxMap:      make(map[int64]types.Address),
		lastChainIdx:     rootKeyChainIdx,
		missingKeysStart: rootKeyChainIdx,
		secret:           aeskey,
	}
	copy(s.desc[:], []byte(desc))
	root, err := newRootBtcAddress(s, rootkey, nil, chaincode,
		createdAt)
	if err != nil {
		return nil, err
	}
	if err := root.verifyKeypairs(); err != nil {
		return nil, err
	}
	if err := root.encrypt(aeskey); err != nil {
		return nil, err
	}
	s.keyGenerator = *root
	rootAddr := s.keyGenerator.Address()
	s.addrMap[getAddressKey(rootAddr)] = &s.keyGenerator
	s.chainIdxMap[rootKeyChainIdx] = rootAddr
	if err := s.Lock(); err != nil {
		return nil, err
	}
	return s, nil
}
New creates and initializes a new Store.  name's and desc's byte length
must not exceed 32 and 256 bytes, respectively.  All address private keys
are encrypted with passphrase.  The key store is returned locked.
package keystore
import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha512"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/Qitmeer/qitmeer-wallet/utils"
	"github.com/Qitmeer/qitmeer/common/hash"
	chainhash "github.com/Qitmeer/qitmeer/common/hash"
	"github.com/Qitmeer/qitmeer/core/address"
	"github.com/Qitmeer/qitmeer/core/protocol"
	"github.com/Qitmeer/qitmeer/core/types"
	"github.com/Qitmeer/qitmeer/crypto/ecc"
	qitec "github.com/Qitmeer/qitmeer/crypto/ecc/secp256k1"
	"github.com/Qitmeer/qitmeer/engine/txscript"
	chaincfg "github.com/Qitmeer/qitmeer/params"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"sync"
	"time"
	"golang.org/x/crypto/ripemd160"
	"github.com/Qitmeer/qitmeer-wallet/internal/legacy/rename"
)
const (
	Filename = "wallet.bin"
	kdfOutputBytes = 32
	maxCommentLen = (1 << 16) - 1
)
const (
	defaultKdfComputeTime = 0.25
	defaultKdfMaxMem      = 32 * 1024 * 1024
)
var (
	ErrAddressNotFound  = errors.New("address not found")
	ErrAlreadyEncrypted = errors.New("private key is already encrypted")
	ErrChecksumMismatch = errors.New("checksum mismatch")
	ErrDuplicate        = errors.New("duplicate key or address")
	ErrMalformedEntry   = errors.New("malformed entry")
	ErrWatchingOnly     = errors.New("keystore is watching-only")
	ErrLocked           = errors.New("keystore is locked")
	ErrWrongPassphrase  = errors.New("wrong passphrase")
)
var fileID = [8]byte{0xba, 'W', 'A', 'L', 'L', 'E', 'T', 0x00}
type entryHeader byte
const (
	addrCommentHeader entryHeader = 1 << iota
	txCommentHeader
	deletedHeader
	scriptHeader
	addrHeader entryHeader = 0
)
func binaryRead(r io.Reader, order binary.ByteOrder, data interface{}) (n int64, err error) {
	var read int
	buf := make([]byte, binary.Size(data))
	if read, err = io.ReadFull(r, buf); err != nil {
		return int64(read), err
	}
	return int64(read), binary.Read(bytes.NewBuffer(buf), order, data)
}
func binaryWrite(w io.Writer, order binary.ByteOrder, data interface{}) (n int64, err error) {
	buf := bytes.Buffer{}
	if err = binary.Write(&buf, order, data); err != nil {
		return 0, err
	}
	written, err := w.Write(buf.Bytes())
	return int64(written), err
}
func pubkeyFromPrivkey(privkey []byte, compress bool) (pubkey []byte) {
	_, pk := ecc.Secp256k1.PrivKeyFromBytes(privkey)
	if compress {
		return pk.SerializeCompressed()
	}
	return pk.SerializeUncompressed()
}
func keyOneIter(passphrase, salt []byte, memReqts uint64) []byte {
	saltedpass := append(passphrase, salt...)
	lutbl := make([]byte, memReqts)
	seed := sha512.Sum512(saltedpass)
	copy(lutbl[:sha512.Size], seed[:])
	for nByte := 0; nByte < (int(memReqts) - sha512.Size); nByte += sha512.Size {
		hash := sha512.Sum512(lutbl[nByte : nByte+sha512.Size])
		copy(lutbl[nByte+sha512.Size:nByte+2*sha512.Size], hash[:])
	}
	x := lutbl[cap(lutbl)-sha512.Size:]
	seqCt := uint32(memReqts / sha512.Size)
	nLookups := seqCt / 2
	for i := uint32(0); i < nLookups; i++ {
		newIdx := binary.LittleEndian.Uint32(x[cap(x)-4:]) % seqCt
		vIdx := newIdx * sha512.Size
		v := lutbl[vIdx : vIdx+sha512.Size]
		for j := 0; j < sha512.Size; j++ {
			x[j] ^= v[j]
		}
		hash := sha512.Sum512(x)
		copy(x, hash[:])
	}
	return x[:kdfOutputBytes]
}
func kdf(passphrase []byte, params *kdfParameters) []byte {
	masterKey := passphrase
	for i := uint32(0); i < params.nIter; i++ {
		masterKey = keyOneIter(masterKey, params.salt[:], params.mem)
	}
	return masterKey
}
func pad(size int, b []byte) []byte {
	if len(b) > size {
		size = len(b)
	}
	p := make([]byte, size)
	copy(p[size-len(b):], b)
	return p
}
func chainedPrivKey(privkey, pubkey, chaincode []byte) ([]byte, error) {
	if len(privkey) != 32 {
		return nil, fmt.Errorf("invalid privkey length %d (must be 32)",
			len(privkey))
	}
	if len(chaincode) != 32 {
		return nil, fmt.Errorf("invalid chaincode length %d (must be 32)",
			len(chaincode))
	}
	switch n := len(pubkey); n {
	case qitec.PubKeyBytesLenUncompressed, qitec.PubKeyBytesLenCompressed:
	default:
		return nil, fmt.Errorf("invalid pubkey length %d", n)
	}
	xorbytes := make([]byte, 32)
	chainMod := chainhash.DoubleHashB(pubkey)
	for i := range xorbytes {
		xorbytes[i] = chainMod[i] ^ chaincode[i]
	}
	chainXor := new(big.Int).SetBytes(xorbytes)
	privint := new(big.Int).SetBytes(privkey)
	t := new(big.Int).Mul(chainXor, privint)
	b := t.Mod(t, qitec.S256().N).Bytes()
	return pad(32, b), nil
}
func chainedPubKey(pubkey, chaincode []byte) ([]byte, error) {
	var compressed bool
	switch n := len(pubkey); n {
	case qitec.PubKeyBytesLenUncompressed:
		compressed = false
	case qitec.PubKeyBytesLenCompressed:
		compressed = true
	default:
		return nil, fmt.Errorf("invalid pubkey length %d", n)
	}
	if len(chaincode) != 32 {
		return nil, fmt.Errorf("invalid chaincode length %d (must be 32)",
			len(chaincode))
	}
	xorbytes := make([]byte, 32)
	chainMod := chainhash.DoubleHashB(pubkey)
	for i := range xorbytes {
		xorbytes[i] = chainMod[i] ^ chaincode[i]
	}
	oldPk, err := qitec.ParsePubKey(pubkey)
	if err != nil {
		return nil, err
	}
	newX, newY := qitec.S256().ScalarMult(oldPk.X, oldPk.Y, xorbytes)
	if err != nil {
		return nil, err
	}
	newPk := &qitec.PublicKey{
		Curve: qitec.S256(),
		X:     newX,
		Y:     newY,
	}
	if compressed {
		return newPk.SerializeCompressed(), nil
	}
	return newPk.SerializeUncompressed(), nil
}
type version struct {
	major         byte
	minor         byte
	bugfix        byte
	autoincrement byte
}
var _ io.ReaderFrom = &version{}
var _ io.WriterTo = &version{}
type readerFromVersion interface {
	readFromVersion(version, io.Reader) (int64, error)
	io.WriterTo
}
func (v version) String() string {
	str := fmt.Sprintf("%d.%d", v.major, v.minor)
	if v.bugfix != 0x00 || v.autoincrement != 0x00 {
		str += fmt.Sprintf(".%d", v.bugfix)
	}
	if v.autoincrement != 0x00 {
		str += fmt.Sprintf(".%d", v.autoincrement)
	}
	return str
}
func (v version) Uint32() uint32 {
	return uint32(v.major)<<6 | uint32(v.minor)<<4 | uint32(v.bugfix)<<2 | uint32(v.autoincrement)
}
func (v *version) ReadFrom(r io.Reader) (int64, error) {
	var versBytes [4]byte
	n, err := io.ReadFull(r, versBytes[:])
	if err != nil {
		return int64(n), err
	}
	v.major = versBytes[0]
	v.minor = versBytes[1]
	v.bugfix = versBytes[2]
	v.autoincrement = versBytes[3]
	return int64(n), nil
}
func (v *version) WriteTo(w io.Writer) (int64, error) {
	versBytes := []byte{
		v.major,
		v.minor,
		v.bugfix,
		v.autoincrement,
	}
	n, err := w.Write(versBytes)
	return int64(n), err
}
func (v version) LT(v2 version) bool {
	switch {
	case v.major < v2.major:
		return true
	case v.minor < v2.minor:
		return true
	case v.bugfix < v2.bugfix:
		return true
	case v.autoincrement < v2.autoincrement:
		return true
	default:
		return false
	}
}
func (v version) EQ(v2 version) bool {
	switch {
	case v.major != v2.major:
		return false
	case v.minor != v2.minor:
		return false
	case v.bugfix != v2.bugfix:
		return false
	case v.autoincrement != v2.autoincrement:
		return false
	default:
		return true
	}
}
func (v version) GT(v2 version) bool {
	switch {
	case v.major > v2.major:
		return true
	case v.minor > v2.minor:
		return true
	case v.bugfix > v2.bugfix:
		return true
	case v.autoincrement > v2.autoincrement:
		return true
	default:
		return false
	}
}
var (
	VersArmory = version{1, 35, 0, 0}
	Vers20LastBlocks = version{1, 36, 0, 0}
	VersUnsetNeedsPrivkeyFlag = version{1, 36, 1, 0}
	VersCurrent = VersUnsetNeedsPrivkeyFlag
)
type varEntries struct {
	store   *Store
	entries []io.WriterTo
}
func (v *varEntries) WriteTo(w io.Writer) (n int64, err error) {
	ss := v.entries
	var written int64
	for _, s := range ss {
		var err error
		if written, err = s.WriteTo(w); err != nil {
			return n + written, err
		}
		n += written
	}
	return n, nil
}
func (v *varEntries) ReadFrom(r io.Reader) (n int64, err error) {
	var read int64
	v.entries = nil
	wts := v.entries
	for {
		var header entryHeader
		if read, err = binaryRead(r, binary.LittleEndian, &header); err != nil {
			if err == io.EOF {
				return n + read, nil
			}
			return n + read, err
		}
		n += read
		var wt io.WriterTo
		switch header {
		case addrHeader:
			var entry addrEntry
			entry.addr.store = v.store
			if read, err = entry.ReadFrom(r); err != nil {
				return n + read, err
			}
			n += read
			wt = &entry
		case scriptHeader:
			var entry scriptEntry
			entry.script.store = v.store
			if read, err = entry.ReadFrom(r); err != nil {
				return n + read, err
			}
			n += read
			wt = &entry
		default:
			return n, fmt.Errorf("unknown entry header: %d", uint8(header))
		}
		if wt != nil {
			wts = append(wts, wt)
			v.entries = wts
		}
	}
}
type netParams chaincfg.Params
func (net *netParams) ReadFrom(r io.Reader) (int64, error) {
	var buf [4]byte
	uint32Bytes := buf[:4]
	n, err := io.ReadFull(r, uint32Bytes)
	n64 := int64(n)
	if err != nil {
		return n64, err
	}
	switch protocol.Network(binary.LittleEndian.Uint32(uint32Bytes)) {
	case protocol.MainNet:
		*net = (netParams)(chaincfg.MainNetParams)
	case protocol.TestNet:
		*net = (netParams)(chaincfg.TestNetParams)
	case protocol.PrivNet:
		*net = (netParams)(chaincfg.PrivNetParams)
	default:
		return n64, errors.New("unknown network")
	}
	return n64, nil
}
func (net *netParams) WriteTo(w io.Writer) (int64, error) {
	var buf [4]byte
	uint32Bytes := buf[:4]
	binary.LittleEndian.PutUint32(uint32Bytes, uint32(net.Net))
	n, err := w.Write(uint32Bytes)
	n64 := int64(n)
	return n64, err
}
type addressKey string
type transactionHashKey string
type comment []byte
func getAddressKey(addr types.Address) addressKey {
	return addressKey(addr.Script())
}
type Store struct {
	dirty bool
	path  string
	dir   string
	file  string
	mtx          sync.RWMutex
	vers         version
	net          *netParams
	flags        walletFlags
	createDate   int64
	name         [32]byte
	desc         [256]byte
	highestUsed  int64
	kdfParams    kdfParameters
	keyGenerator btcAddress
	recent recentBlocks
	addrMap map[addressKey]walletAddress
	passphrase       []byte
	secret           []byte
	chainIdxMap      map[int64]types.Address
	importedAddrs    []walletAddress
	lastChainIdx     int64
	missingKeysStart int64
}