func ValidateEnvelope(e *Envelope) error {
	if e == nil {
		return ErrMissingEnvelope
	}
	if err := ValidateBytes(e.EntryKey, DocumentKeyLength, "EntryKey"); err != nil {
		return err
	}
	if err := ValidatePublicKey(e.AuthorPublicKey); err != nil {
		return err
	}
	if err := ValidatePublicKey(e.ReaderPublicKey); err != nil {
		return err
	}
	if err := ValidateBytes(e.EekCiphertext, EEKCiphertextLength, "EntryEncryptionKeys"); err != nil {
		return err
	}
	if err := ValidateHMAC256(e.EekCiphertextMac); err != nil {
		return err
	}
	return nil
}
ValidateEnvelope checks that all fields of an Envelope are populated and have the expected
lengths.
package api
import (
	"bytes"
	"crypto/sha256"
	"errors"
	"fmt"
	cerrors "github.com/drausin/libri/libri/common/errors"
	"github.com/drausin/libri/libri/common/id"
	"github.com/golang/protobuf/proto"
)
const (
	ECPubKeyLength = 33
	DocumentKeyLength = id.Length
	AESKeyLength = 32
	PageIVSeedLength = 32
	HMACKeyLength = 32
	BlockCipherIVLength = 12
	KEKLength = AESKeyLength + BlockCipherIVLength + HMACKeyLength
	EEKLength = AESKeyLength +
		PageIVSeedLength +
		HMACKeyLength +
		BlockCipherIVLength
	EEKCiphertextLength = EEKLength + 16
	HMAC256Length = sha256.Size
)
var (
	ErrUnexpectedDocumentType = errors.New("unexpected document type")
	ErrUnknownDocumentType = errors.New("unknown document type")
	ErrUnexpectedKey = errors.New("unexpected key for value")
	ErrMissingDocument = errors.New("missing document")
	ErrMissingEnvelope = errors.New("missing envelope")
	ErrMissingEntry = errors.New("missing entry")
	ErrMissingPage = errors.New("missing page")
	ErrZeroCreatedTime = errors.New("created time is zero")
	ErrDiffAuthorPubs = errors.New("page and entry have different author public keys")
	ErrMissingPageKeys = errors.New("missing page keys")
	ErrEmptyPageKeys = errors.New("empty page keys")
)
func GetKey(value proto.Message) (id.ID, error) {
	valueBytes, err := proto.Marshal(value)
	if err != nil {
		return nil, err
	}
	hash := sha256.Sum256(valueBytes)
	return id.FromBytes(hash[:]), nil
}
func GetAuthorPub(d *Document) []byte {
	switch c := d.Contents.(type) {
	case *Document_Entry:
		return c.Entry.AuthorPublicKey
	case *Document_Page:
		return c.Page.AuthorPublicKey
	case *Document_Envelope:
		return c.Envelope.AuthorPublicKey
	}
	panic(ErrUnknownDocumentType)
}
func GetEntryPageKeys(entryDoc *Document) ([]id.ID, error) {
	entry, ok := entryDoc.Contents.(*Document_Entry)
	if !ok {
		return nil, ErrUnexpectedDocumentType
	}
	if entry.Entry.Page != nil {
		return nil, nil
	}
	if entry.Entry.PageKeys != nil {
		pageKeyBytes := entry.Entry.PageKeys
		pageKeys := make([]id.ID, len(pageKeyBytes))
		for i, keyBytes := range pageKeyBytes {
			pageKeys[i] = id.FromBytes(keyBytes)
		}
		return pageKeys, nil
	}
	return nil, ErrUnexpectedDocumentType
}
func GetPageDocument(page *Page) (*Document, id.ID, error) {
	pageDoc := &Document{
		Contents: &Document_Page{
			Page: page,
		},
	}
	pageKey, err := GetKey(pageDoc)
	cerrors.MaybePanic(err)  
	return pageDoc, pageKey, nil
}
func ValidateDocument(d *Document) error {
	if d == nil {
		return ErrMissingDocument
	}
	switch c := d.Contents.(type) {
	case *Document_Envelope:
		return ValidateEnvelope(c.Envelope)
	case *Document_Entry:
		return ValidateEntry(c.Entry)
	case *Document_Page:
		return ValidatePage(c.Page)
	}
	return ErrUnknownDocumentType
}