func newClient(id []byte, clientKey keys.KeyMaterial, store ReadWriteSeeker) (*client, error) {
	if len(id) == 0 {
		return nil, errors.New("client id must not be empty")
	}
	c := &client{
		Key:            clientKey,
		TopicKeys:      make(map[string]keys.TopicKey),
		ReceivingTopic: TopicForID(id),
		store: store,
	}
	c.ID = make([]byte, len(id))
	copy(c.ID, id)
	log.SetPrefix("e4client\t")
	if err := c.save(); err != nil {
		return nil, err
	}
	return c, nil
}
newClient creates a new client, generating a random ID if they are empty
package e4
import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"sync"
	"time"
	miscreant "github.com/miscreant/miscreant.go"
	"golang.org/x/crypto/ed25519"
	e4crypto "github.com/teserakt-io/e4go/crypto"
	"github.com/teserakt-io/e4go/keys"
)
const (
	idTopicPrefix = "e4/"
)
var (
	ErrTopicKeyNotFound = errors.New("topic key not found")
	ErrUnsupportedOperation = errors.New("this operation is not supported")
)
type Client interface {
	ProtectMessage(payload []byte, topic string) ([]byte, error)
	Unprotect(protected []byte, topic string) ([]byte, error)
	IsReceivingTopic(topic string) bool
	GetReceivingTopic() string
	setIDKey(key []byte) error
	setPubKey(key ed25519.PublicKey, clientID []byte) error
	removePubKey(clientID []byte) error
	resetPubKeys() error
	getPubKeys() (map[string]ed25519.PublicKey, error)
	setTopicKey(key, topicHash []byte) error
	removeTopic(topicHash []byte) error
	resetTopics() error
	setC2Key(newC2PubKey e4crypto.Curve25519PublicKey) error
}
type client struct {
	ID []byte
	TopicKeys map[string]keys.TopicKey
	Key keys.KeyMaterial
	ReceivingTopic string
	store ReadWriteSeeker
	lock  sync.RWMutex
}
var _ Client = (*client)(nil)
type ClientConfig interface {
	genNewClient(store ReadWriteSeeker) (*client, error)
}
type SymIDAndKey struct {
	ID  []byte
	Key []byte
}
type SymNameAndPassword struct {
	Name     string
	Password string
}
type PubIDAndKey struct {
	ID       []byte
	Key      e4crypto.Ed25519PrivateKey
	C2PubKey e4crypto.Curve25519PublicKey
}
type PubNameAndPassword struct {
	Name     string
	Password string
	C2PubKey e4crypto.Curve25519PublicKey
}
var _ ClientConfig = (*SymIDAndKey)(nil)
var _ ClientConfig = (*SymNameAndPassword)(nil)
var _ ClientConfig = (*PubIDAndKey)(nil)
var _ ClientConfig = (*PubNameAndPassword)(nil)
func (ik *SymIDAndKey) genNewClient(store ReadWriteSeeker) (*client, error) {
	var newID []byte
	if len(ik.ID) == 0 {
		newID = e4crypto.RandomID()
	} else {
		newID = make([]byte, len(ik.ID))
		copy(newID, ik.ID)
	}
	symKeyMaterial, err := keys.NewSymKeyMaterial(ik.Key)
	if err != nil {
		return nil, fmt.Errorf("failed to created symkey from key: %v", err)
	}
	return newClient(newID, symKeyMaterial, store)
}
func (np *SymNameAndPassword) genNewClient(store ReadWriteSeeker) (*client, error) {
	id := e4crypto.HashIDAlias(np.Name)
	key, err := e4crypto.DeriveSymKey(np.Password)
	if err != nil {
		return nil, fmt.Errorf("failed to derive key from password: %v", err)
	}
	symKeyMaterial, err := keys.NewSymKeyMaterial(key)
	if err != nil {
		return nil, fmt.Errorf("failed to created symkey from key: %v", err)
	}
	return newClient(id, symKeyMaterial, store)
}
func (ik *PubIDAndKey) genNewClient(store ReadWriteSeeker) (*client, error) {
	var newID []byte
	if len(ik.ID) == 0 {
		newID = e4crypto.RandomID()
	} else {
		newID = make([]byte, len(ik.ID))
		copy(newID, ik.ID)
	}
	pubKeyMaterialKey, err := keys.NewPubKeyMaterial(newID, ik.Key, ik.C2PubKey)
	if err != nil {
		return nil, fmt.Errorf("failed to create ed25519key from key: %v", err)
	}
	return newClient(newID, pubKeyMaterialKey, store)
}
func (np *PubNameAndPassword) genNewClient(store ReadWriteSeeker) (*client, error) {
	id := e4crypto.HashIDAlias(np.Name)
	key, err := e4crypto.Ed25519PrivateKeyFromPassword(np.Password)
	if err != nil {
		return nil, fmt.Errorf("failed to create ed25519 key from password: %v", err)
	}
	pubKeyMaterialKey, err := keys.NewPubKeyMaterial(id, key, np.C2PubKey)
	if err != nil {
		return nil, fmt.Errorf("failed to create ed25519key from key: %v", err)
	}
	return newClient(id, pubKeyMaterialKey, store)
}
func (np *PubNameAndPassword) PubKey() (e4crypto.Ed25519PublicKey, error) {
	key, err := e4crypto.Ed25519PrivateKeyFromPassword(np.Password)
	if err != nil {
		return nil, fmt.Errorf("failed to create ed25519 key from password: %v", err)
	}
	edKey, ok := ed25519.PrivateKey(key).Public().(ed25519.PublicKey)
	if !ok {
		return nil, errors.New("failed to cast key to ed25519.PublicKey")
	}
	return edKey, nil
}
type ClientOption interface {
	apply(c *client)
}
type withReceivingTopic string
func (w withReceivingTopic) apply(c *client) {
	c.ReceivingTopic = string(w)
}
func WithReceivingTopic(topic string) ClientOption {
	return withReceivingTopic(topic)
}
func NewClient(config ClientConfig, store ReadWriteSeeker, opts ...ClientOption) (Client, error) {
	c, err := config.genNewClient(store)
	if err != nil {
		return nil, err
	}
	for _, opt := range opts {
		opt.apply(c)
	}
	return c, nil
}