func SignProfile(name, location, image string, km km.KeyManager) (*Profile, error) {
	chatIDKeys, err := km.ChatIdKeyPair()
	if err != nil {
		return nil, err
	}
	idPubKeyStr, err := km.IdentityPublicKey()
	if err != nil {
		return nil, err
	}
	idPubKeyRaw, err := hex.DecodeString(idPubKeyStr)
	if err != nil {
		return nil, err
	}
	ethPubKeyStr, err := km.GetEthereumPublicKey()
	if err != nil {
		return nil, err
	}
	ethPubKeyRaw, err := hex.DecodeString(ethPubKeyStr)
	if err != nil {
		return nil, err
	}
	p := Profile{
		Information: Information{
			Name:           name,
			Location:       location,
			Image:          image,
			ChatIDKey:      chatIDKeys.PublicKey,
			Timestamp:      time.Now(),
			Version:        profileVersion,
			IdentityPubKey: idPubKeyRaw,
			EthereumPubKey: ethPubKeyRaw,
		},
	}
	hash, err := p.Hash()
	if err != nil {
		return nil, err
	}
	p.Signatures.IdentityKey, err = km.IdentitySign(hash)
	if err != nil {
		return nil, err
	}
	p.Signatures.EthereumKey, err = km.EthereumSign(sha256.Sum256(hash))
	return &p, nil
}
sign the metadata with identity and ethereum key
package profile
import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"time"
	"encoding/binary"
	km "github.com/Bit-Nation/panthalassa/keyManager"
	pb "github.com/Bit-Nation/protobuffers"
	x3dh "github.com/Bit-Nation/x3dh"
	common "github.com/ethereum/go-ethereum/common"
	crypto "github.com/ethereum/go-ethereum/crypto"
	mh "github.com/multiformats/go-multihash"
	ed25519 "golang.org/x/crypto/ed25519"
)
const (
	profileVersion = 2
)
var (
	InvalidIdentityPublicKey = errors.New("identity public key invalid - must have 32 bytes")
	InvalidEthereumPublicKey = errors.New("ethereum public key invalid - must have 33 bytes")
	InvalidChatIDKey         = errors.New("chat identity key invalid - must have 32 bytes")
)
type Information struct {
	Name           string
	Location       string
	Image          string
	IdentityPubKey []byte
	EthereumPubKey []byte
	ChatIDKey      x3dh.PublicKey
	Timestamp      time.Time
	Version        uint8
}
type Signatures struct {
	IdentityKey []byte
	EthereumKey []byte
}
type Profile struct {
	Information Information
	Signatures  Signatures
}
func ProtobufToProfile(prof *pb.Profile) (*Profile, error) {
	if len(prof.IdentityPubKey) != 32 {
		return nil, InvalidIdentityPublicKey
	}
	if len(prof.EthereumPubKey) != 33 {
		return nil, InvalidEthereumPublicKey
	}
	if len(prof.ChatIdentityPubKey) != 32 {
		return nil, InvalidChatIDKey
	}
	chatIDPubKey := x3dh.PublicKey{}
	copy(chatIDPubKey[:], prof.ChatIdentityPubKey[:32])
	return &Profile{
		Information: Information{
			Name:           prof.Name,
			Location:       prof.Location,
			Image:          prof.Image,
			IdentityPubKey: prof.IdentityPubKey,
			EthereumPubKey: prof.EthereumPubKey,
			ChatIDKey:      chatIDPubKey,
			Timestamp:      time.Unix(prof.Timestamp, 0),
			Version:        uint8(prof.Version),
		},
		Signatures: Signatures{
			IdentityKey: prof.IdentityKeySignature,
			EthereumKey: prof.EthereumKeySignature,
		},
	}, nil
}
func (p *Profile) Hash() (mh.Multihash, error) {
	b := bytes.NewBuffer([]byte(p.Information.Name))
	timeStamp := make([]byte, binary.MaxVarintLen64)
	n := binary.PutVarint(timeStamp, p.Information.Timestamp.Unix())
	toWrite := [][]byte{
		[]byte(p.Information.Location),
		[]byte(p.Information.Image),
		p.Information.IdentityPubKey,
		p.Information.EthereumPubKey,
		p.Information.ChatIDKey[:],
		timeStamp[:n],
	}
	for _, tw := range toWrite {
		if _, err := b.Write(tw); err != nil {
			return nil, err
		}
	}
	if err := b.WriteByte(p.Information.Version); err != nil {
		return nil, err
	}
	return mh.Sum(b.Bytes(), mh.SHA2_256, -1)
}
func (p *Profile) IdentityPublicKey() (ed25519.PublicKey, error) {
	if len(p.Information.IdentityPubKey) != 32 {
		return nil, InvalidIdentityPublicKey
	}
	return p.Information.IdentityPubKey, nil
}
func (p *Profile) EthereumPublicKey() ([]byte, error) {
	if len(p.Information.EthereumPubKey) != 33 {
		return nil, InvalidEthereumPublicKey
	}
	return p.Information.EthereumPubKey, nil
}
func (p *Profile) ValidIdentitySignature(msg, signature []byte) (bool, error) {
	idPubKey, err := p.IdentityPublicKey()
	if err != nil {
		return false, err
	}
	return ed25519.Verify(idPubKey, msg, signature), nil
}
func (p *Profile) ValidEthereumSignature(msg [32]byte, signature [65]byte) (bool, error) {
	ethPubKey, err := p.EthereumPublicKey()
	if err != nil {
		return false, err
	}
	return crypto.VerifySignature(ethPubKey, msg[:], signature[:64]), nil
}
func (p Profile) SignaturesValid() (bool, error) {
	h, err := p.Hash()
	if err != nil {
		return false, err
	}
	valid, err := p.ValidIdentitySignature(h, p.Signatures.IdentityKey)
	if err != nil {
		return false, err
	}
	if !valid {
		return false, errors.New("invalid identity signature")
	}
	var sig [65]byte
	copy(sig[:], p.Signatures.EthereumKey[:65])
	valid, err = p.ValidEthereumSignature(sha256.Sum256(h), sig)
	if err != nil {
		return false, err
	}
	if !valid {
		return false, errors.New("invalid ethereum signature")
	}
	return true, nil
}
func (p *Profile) ToProtobuf() (*pb.Profile, error) {
	if len(p.Information.IdentityPubKey) != 32 {
		return nil, InvalidIdentityPublicKey
	}
	if len(p.Information.EthereumPubKey) != 33 {
		return nil, InvalidEthereumPublicKey
	}
	if len(p.Information.ChatIDKey) != 32 {
		return nil, InvalidChatIDKey
	}
	pp := pb.Profile{}
	pp.Name = p.Information.Name
	pp.Location = p.Information.Location
	pp.Image = p.Information.Image
	pp.IdentityPubKey = p.Information.IdentityPubKey
	pp.EthereumPubKey = p.Information.EthereumPubKey
	pp.ChatIdentityPubKey = p.Information.ChatIDKey[:]
	pp.Timestamp = p.Information.Timestamp.Unix()
	pp.Version = uint32(p.Information.Version)
	pp.IdentityKeySignature = p.Signatures.IdentityKey
	pp.EthereumKeySignature = p.Signatures.EthereumKey
	return &pp, nil
}
func (p *Profile) EthereumAddress() (common.Address, error) {
	valid, err := p.SignaturesValid()
	if err != nil {
		return common.Address{}, err
	}
	if !valid {
		return common.Address{}, errors.New("invalid profile signature")
	}
	ethPubKey, err := p.EthereumPublicKey()
	if err != nil {
		return common.Address{}, err
	}
	decPubKey, err := crypto.DecompressPubkey(ethPubKey)
	if err != nil {
		return common.Address{}, err
	}
	return crypto.PubkeyToAddress(*decPubKey), nil
}