func (s *SecureEnclave) UpdatePartyInfo(encoded []byte) {
	s.PartyInfo.UpdatePartyInfo(encoded)
}
UpdatePartyInfo applies the provided binary encoded party details to the SecureEnclave's
own party details store.
package enclave
import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/blk-io/crux/api"
	"github.com/blk-io/crux/storage"
	"github.com/blk-io/crux/utils"
	"github.com/kevinburke/nacl"
	"github.com/kevinburke/nacl/box"
	"github.com/kevinburke/nacl/secretbox"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	"path/filepath"
	"strings"
)
type SecureEnclave struct {
	Db         storage.DataStore                   
	PubKeys    []nacl.Key                          
	PrivKeys   []nacl.Key                          
	selfPubKey nacl.Key                            
	PartyInfo  api.PartyInfo                       
	keyCache   map[nacl.Key]map[nacl.Key]nacl.Key  
	client     utils.HttpClient                    
	grpc       bool
}
func Init(
	db storage.DataStore,
	pubKeyFiles, privKeyFiles []string,
	pi api.PartyInfo,
	client utils.HttpClient, grpc bool) *SecureEnclave {
	pubKeys, err := loadPubKeys(pubKeyFiles)
	if err != nil {
		log.Fatalf("Unable to load public key files: %s, error: %v", pubKeyFiles, err)
	}
	privKeys, err := loadPrivKeys(privKeyFiles)
	if err != nil {
		log.Fatalf("Unable to load private key files: %s, error: %v", privKeyFiles, err)
	}
	enc := SecureEnclave{
		Db:        db,
		PubKeys:   pubKeys,
		PrivKeys:  privKeys,
		PartyInfo: pi,
		client:    client,
		grpc:      grpc,
	}
	enc.keyCache = make(map[nacl.Key]map[nacl.Key]nacl.Key)
	enc.selfPubKey = nacl.NewKey()
	for _, pubKey := range enc.PubKeys {
		enc.keyCache[pubKey] = make(map[nacl.Key]nacl.Key)
		enc.resolveSharedKey(enc.PrivKeys[0], pubKey, enc.selfPubKey)
	}
	return &enc
}
func (s *SecureEnclave) Store(
	message *[]byte, sender []byte, recipients [][]byte) ([]byte, error) {
	var err error
	var senderPubKey, senderPrivKey nacl.Key
	if len(sender) == 0 {
		senderPubKey = s.PubKeys[0]
		senderPrivKey = s.PrivKeys[0]
	} else {
		senderPubKey, err = utils.ToKey(sender)
		if err != nil {
			log.WithField("senderPubKey", sender).Errorf(
				"Unable to load sender public key, %v", err)
			return nil, err
		}
		senderPrivKey, err = s.resolvePrivateKey(senderPubKey)
		if err != nil {
			log.WithField("senderPubKey", sender).Errorf(
				"Unable to locate private key for sender public key, %v", err)
			return nil, err
		}
	}
	return s.store(message, senderPubKey, senderPrivKey, recipients)
}
func (s *SecureEnclave) store(
	message *[]byte,
	senderPubKey, senderPrivKey nacl.Key,
	recipients [][]byte) ([]byte, error) {
	var toSelf bool
	if len(recipients) == 0 {
		toSelf = true
		recipients = [][]byte{(*s.selfPubKey)[:]}
	} else {
		toSelf = false
	}
	epl, masterKey := createEncryptedPayload(message, senderPubKey, recipients)
	for i, recipient := range recipients {
		recipientKey, err := utils.ToKey(recipient)
		if err != nil {
			log.WithField("recipientKey", recipientKey).Errorf(
				"Unable to load recipient, %v", err)
			continue
		}
		if bytes.Equal((*recipientKey)[:], (*senderPubKey)[:]) {
			log.WithField("recipientKey", recipientKey).Errorf(
				"Sender cannot be recipient, %v", err)
			continue
		}
		sharedKey := s.resolveSharedKey(senderPrivKey, senderPubKey, recipientKey)
		sealedBox := sealPayload(epl.RecipientNonce, masterKey, sharedKey)
		epl.RecipientBoxes[i] = sealedBox
	}
	encodedEpl := api.EncodePayloadWithRecipients(epl, recipients)
	digest, err := s.storePayload(epl, encodedEpl)
	if !toSelf {
		for i, recipient := range recipients {
			recipientEpl := api.EncryptedPayload{
				Sender:         senderPubKey,
				CipherText:     epl.CipherText,
				Nonce:          epl.Nonce,
				RecipientBoxes: [][]byte{epl.RecipientBoxes[i]},
				RecipientNonce: epl.RecipientNonce,
			}
			log.WithFields(log.Fields{
				"recipient": hex.EncodeToString(recipient), "digest": hex.EncodeToString(digest),
			}).Debug("Publishing payload")
			s.publishPayload(recipientEpl, recipient)
		}
	}
	return digest, err
}
func createEncryptedPayload(
	message *[]byte, senderPubKey nacl.Key, recipients [][]byte) (api.EncryptedPayload, nacl.Key) {
	nonce := nacl.NewNonce()
	masterKey := nacl.NewKey()
	recipientNonce := nacl.NewNonce()
	sealedMessage := secretbox.Seal([]byte{}, *message, nonce, masterKey)
	return api.EncryptedPayload{
		Sender:         senderPubKey,
		CipherText:     sealedMessage,
		Nonce:          nonce,
		RecipientBoxes: make([][]byte, len(recipients)),
		RecipientNonce: recipientNonce,
	}, masterKey
}
func (s *SecureEnclave) publishPayload(epl api.EncryptedPayload, recipient []byte) {
	key, err := utils.ToKey(recipient)
	if err != nil {
		log.WithField("recipient", recipient).Errorf(
			"Unable to decode key for recipient, error: %v", err)
	}
	if url, ok := s.PartyInfo.GetRecipient(key); ok {
		encoded := api.EncodePayloadWithRecipients(epl, [][]byte{})
		if s.grpc {
			api.PushGrpc(encoded, url, epl)
		} else {
			api.Push(encoded, url, s.client)
		}
	} else {
		log.WithField("recipientKey", hex.EncodeToString(recipient)).Error("Unable to resolve host")
	}
}
func (s *SecureEnclave) resolveSharedKey(
	senderPrivKey, senderPubKey, recipientPubKey nacl.Key) nacl.Key {
	keyCache, ok := s.keyCache[senderPubKey]
	if !ok {
		keyCache = make(map[nacl.Key]nacl.Key)
		s.keyCache[senderPubKey] = keyCache
	}
	sharedKey, ok := keyCache[recipientPubKey]
	if !ok {
		sharedKey = box.Precompute(recipientPubKey, senderPrivKey)
		keyCache[recipientPubKey] = sharedKey
	}
	return sharedKey
}
func (s *SecureEnclave) resolvePrivateKey(publicKey nacl.Key) (nacl.Key, error) {
	for i, key := range s.PubKeys {
		if bytes.Equal((*publicKey)[:], (*key)[:]) {
			return s.PrivKeys[i], nil
		}
	}
	return nil, fmt.Errorf("unable to find private key for public key: %s",
		hex.EncodeToString((*publicKey)[:]))
}
func (s *SecureEnclave) StorePayload(encoded []byte) ([]byte, error) {
	epl, _ := api.DecodePayloadWithRecipients(encoded)
	return s.storePayload(epl, encoded)
}
func (s *SecureEnclave) StorePayloadGrpc(epl api.EncryptedPayload, encoded []byte) ([]byte, error) {
	return s.storePayload(epl, encoded)
}
func (s *SecureEnclave) storePayload(epl api.EncryptedPayload, encoded []byte) ([]byte, error) {
	digestHash := utils.Sha3Hash(epl.CipherText)
	err := s.Db.Write(&digestHash, &encoded)
	return digestHash, err
}
func sealPayload(
	recipientNonce nacl.Nonce,
	masterKey nacl.Key,
	sharedKey nacl.Key) []byte {
	return box.SealAfterPrecomputation(
		[]byte{},
		(*masterKey)[:],
		recipientNonce,
		sharedKey)
}
func (s *SecureEnclave) RetrieveDefault(digestHash *[]byte) ([]byte, error) {
	key := (*s.PubKeys[0])[:]
	return s.Retrieve(digestHash, &key)
}
func (s *SecureEnclave) Retrieve(digestHash *[]byte, to *[]byte) ([]byte, error) {
	encoded, err := s.Db.Read(digestHash)
	if err != nil {
		return nil, err
	}
	epl, recipients := api.DecodePayloadWithRecipients(*encoded)
	masterKey := new([nacl.KeySize]byte)
	var senderPubKey, senderPrivKey, recipientPubKey, sharedKey nacl.Key
	if len(recipients) == 0 {
		recipientPubKey = epl.Sender
		senderPubKey, err = utils.ToKey(*to)
		if err != nil {
			return nil, err
		}
	} else {
		senderPubKey = epl.Sender
		recipientPubKey, err = utils.ToKey(recipients[0])
		if err != nil {
			return nil, err
		}
	}
	senderPrivKey, err = s.resolvePrivateKey(senderPubKey)
	if err != nil {
		return nil, err
	}
	sharedKey = s.resolveSharedKey(senderPrivKey, senderPubKey, recipientPubKey)
	_, ok := secretbox.Open(masterKey[:0], epl.RecipientBoxes[0], epl.RecipientNonce, sharedKey)
	if !ok {
		return nil, errors.New("unable to open master key secret box")
	}
	var payload []byte
	payload, ok = secretbox.Open(payload[:0], epl.CipherText, epl.Nonce, masterKey)
	if !ok {
		return payload, errors.New("unable to open payload secret box")
	}
	return payload, nil
}
func (s *SecureEnclave) RetrieveFor(digestHash *[]byte, reqRecipient *[]byte) (*[]byte, error) {
	encoded, err := s.Db.Read(digestHash)
	if err != nil {
		return nil, err
	}
	epl, recipients := api.DecodePayloadWithRecipients(*encoded)
	for i, recipient := range recipients {
		if bytes.Equal(*reqRecipient, recipient) {
			recipientEpl := api.EncryptedPayload{
				Sender:         epl.Sender,
				CipherText:     epl.CipherText,
				Nonce:          epl.Nonce,
				RecipientBoxes: [][]byte{epl.RecipientBoxes[i]},
				RecipientNonce: epl.RecipientNonce,
			}
			encoded := api.EncodePayload(recipientEpl)
			return &encoded, nil
		}
	}
	return nil, fmt.Errorf("invalid recipient %x requested for payload", reqRecipient)
}
func (s *SecureEnclave) RetrieveAllFor(reqRecipient *[]byte) error {
	return s.Db.ReadAll(func(key, value *[]byte) {
		epl, recipients := api.DecodePayloadWithRecipients(*value)
		for i, recipient := range recipients {
			if bytes.Equal(*reqRecipient, recipient) {
				recipientEpl := api.EncryptedPayload{
					Sender:         epl.Sender,
					CipherText:     epl.CipherText,
					Nonce:          epl.Nonce,
					RecipientBoxes: [][]byte{epl.RecipientBoxes[i]},
					RecipientNonce: epl.RecipientNonce,
				}
				func() {
					go s.publishPayload(recipientEpl, *reqRecipient)
				}()
			}
		}
	})
}
func (s *SecureEnclave) Delete(digestHash *[]byte) error {
	return s.Db.Delete(digestHash)
}