func (ckf ComputedKeyFamily) FindActiveSibkeyAtTime(kid keybase1.KID, t time.Time) (key GenericKey, cki ComputedKeyInfo, err error) {
	liveCki, err := ckf.getCkiIfActiveAtTime(kid, t)
	if liveCki == nil || err != nil {
	} else if !liveCki.Sibkey {
		err = BadKeyError{fmt.Sprintf("The key '%s' wasn't delegated as a sibkey", kid)}
	} else {
		key, err = ckf.FindKeyWithKIDUnsafe(kid)
		cki = *liveCki
	}
	return
}
As FindActiveSibkey, but for a specific time. Note that going back in time
only affects expiration, not revocation. Thus this function is mainly useful
for validating the sigchain, when each delegation and revocation is getting
replayed in order.
package libkb
import (
	"fmt"
	"time"
	keybase1 "github.com/keybase/client/go/protocol"
	jsonw "github.com/keybase/go-jsonw"
)
type KeybaseTime struct {
	Unix  int64  
	Chain int    
}
type ComputedKeyInfo struct {
	Contextified
	Status KeyStatus
	Eldest bool
	Sibkey bool
	CTime int64  
	ETime int64  
	Parent keybase1.KID
	Subkey keybase1.KID
	Delegations map[keybase1.SigID]keybase1.KID
	DelegatedAt *KeybaseTime
	RevokedAt *KeybaseTime
	RevokedBy keybase1.KID
	ActivePGPHash string
}
func (cki ComputedKeyInfo) GetCTime() time.Time {
	return time.Unix(cki.CTime, 0)
}
func (cki ComputedKeyInfo) GetETime() time.Time {
	return UnixToTimeMappingZero(cki.ETime)
}
type ComputedKeyInfos struct {
	Contextified
	dirty bool  
	Infos map[keybase1.KID]*ComputedKeyInfo
	Sigs map[keybase1.SigID]*ComputedKeyInfo
	Devices map[keybase1.DeviceID]*Device
	KIDToDeviceID map[keybase1.KID]keybase1.DeviceID
}
type RawKeyFamily struct {
	AllBundles []string `json:"all_bundles"`
}
type PGPKeySet struct {
	Contextified
	PermissivelyMergedKey *PGPKeyBundle
	KeysByHash            map[string]*PGPKeyBundle
}
func (s *PGPKeySet) addKey(key *PGPKeyBundle) error {
	fullHash, err := key.FullHash()
	if err != nil {
		return err
	}
	s.G().Log.Debug("adding PGP kid %s with full hash %s", key.GetKID().String(), fullHash)
	s.KeysByHash[fullHash] = key
	strippedKey := key.StripRevocations()
	if s.PermissivelyMergedKey == nil {
		s.PermissivelyMergedKey = strippedKey
	} else {
		s.PermissivelyMergedKey.MergeKey(strippedKey)
	}
	return nil
}
type KeyFamily struct {
	pgp2kid map[PGPFingerprint]keybase1.KID
	kid2pgp map[keybase1.KID]PGPFingerprint
	AllKIDs map[keybase1.KID]bool
	PGPKeySets map[keybase1.KID]*PGPKeySet
	SingleKeys map[keybase1.KID]GenericKey  
	BundlesForTesting []string
	Contextified
}
type ComputedKeyFamily struct {
	Contextified
	kf  *KeyFamily
	cki *ComputedKeyInfos
}
func (cki *ComputedKeyInfos) Insert(k keybase1.KID, i *ComputedKeyInfo) {
	cki.Infos[k] = i
	cki.dirty = true
}
func (cki *ComputedKeyInfos) PaperDevices() []*Device {
	var d []*Device
	for _, v := range cki.Devices {
		if v.Status == nil {
			continue
		}
		if *v.Status != DeviceStatusActive {
			continue
		}
		if v.Type != DeviceTypePaper {
			continue
		}
		d = append(d, v)
	}
	return d
}
func (cki ComputedKeyInfos) ShallowCopy() *ComputedKeyInfos {
	ret := &ComputedKeyInfos{
		dirty:         cki.dirty,
		Infos:         make(map[keybase1.KID]*ComputedKeyInfo, len(cki.Infos)),
		Sigs:          make(map[keybase1.SigID]*ComputedKeyInfo, len(cki.Sigs)),
		Devices:       make(map[keybase1.DeviceID]*Device, len(cki.Devices)),
		KIDToDeviceID: make(map[keybase1.KID]keybase1.DeviceID, len(cki.KIDToDeviceID)),
	}
	for k, v := range cki.Infos {
		ret.Infos[k] = v
	}
	for k, v := range cki.Sigs {
		ret.Sigs[k] = v
	}
	for k, v := range cki.Devices {
		ret.Devices[k] = v
	}
	for k, v := range cki.KIDToDeviceID {
		ret.KIDToDeviceID[k] = v
	}
	return ret
}
func NewComputedKeyInfos(g *GlobalContext) *ComputedKeyInfos {
	return &ComputedKeyInfos{
		Contextified:  NewContextified(g),
		Infos:         make(map[keybase1.KID]*ComputedKeyInfo),
		Sigs:          make(map[keybase1.SigID]*ComputedKeyInfo),
		Devices:       make(map[keybase1.DeviceID]*Device),
		KIDToDeviceID: make(map[keybase1.KID]keybase1.DeviceID),
	}
}
func NewComputedKeyInfo(eldest, sibkey bool, status KeyStatus, ctime, etime int64, activePGPHash string) ComputedKeyInfo {
	return ComputedKeyInfo{
		Eldest:        eldest,
		Sibkey:        sibkey,
		Status:        status,
		CTime:         ctime,
		ETime:         etime,
		Delegations:   make(map[keybase1.SigID]keybase1.KID),
		ActivePGPHash: activePGPHash,
	}
}
func (cki ComputedKeyInfos) InsertLocalEldestKey(kid keybase1.KID) {
	eldestCki := NewComputedKeyInfo(true, true, KeyUncancelled, 0, 0, ""  )
	cki.Insert(kid, &eldestCki)
}
func (cki ComputedKeyInfos) InsertServerEldestKey(eldestKey GenericKey, un NormalizedUsername) error {
	kbid := KeybaseIdentity(un)
	if pgp, ok := eldestKey.(*PGPKeyBundle); ok {
		match, ctime, etime := pgp.CheckIdentity(kbid)
		if match {
			eldestCki := NewComputedKeyInfo(true, true, KeyUncancelled, ctime, etime, ""  )
			cki.Insert(eldestKey.GetKID(), &eldestCki)
			return nil
		}
		return KeyFamilyError{"InsertServerEldestKey found a non-matching eldest key."}
	}
	return KeyFamilyError{"InsertServerEldestKey found a non-PGP key."}
}
func (ckf ComputedKeyFamily) InsertEldestLink(tcl TypedChainLink, username NormalizedUsername) (err error) {
	kid := tcl.GetKID()
	key, err := ckf.FindKeyWithKIDUnsafe(kid)
	if err != nil {
		return
	}
	var ctimeKb, etimeKb int64 = 0, 0
	ctimeKb = tcl.GetCTime().Unix()
	etimeKb = tcl.GetETime().Unix()
	var ctimePGP, etimePGP int64 = -1, -1
	if pgp, ok := key.(*PGPKeyBundle); ok {
		kbid := KeybaseIdentity(username)
		_, ctimePGP, etimePGP = pgp.CheckIdentity(kbid)
	}
	var ctime int64
	if ctimePGP >= 0 {
		ctime = ctimePGP
	} else {
		ctime = ctimeKb
	}
	var etime int64
	if etimePGP >= 0 {
		etime = etimePGP
	} else {
		etime = etimeKb
	}
	eldestCki := NewComputedKeyInfo(true, true, KeyUncancelled, ctime, etime, tcl.GetPGPFullHash())
	ckf.cki.Insert(kid, &eldestCki)
	return nil
}
func ParseKeyFamily(g *GlobalContext, jw *jsonw.Wrapper) (ret *KeyFamily, err error) {
	defer g.Trace("ParseKeyFamily", func() error { return err })()
	if jw == nil || jw.IsNil() {
		err = KeyFamilyError{"nil record from server"}
		return
	}
	kf := KeyFamily{
		Contextified: NewContextified(g),
		pgp2kid:      make(map[PGPFingerprint]keybase1.KID),
		kid2pgp:      make(map[keybase1.KID]PGPFingerprint),
	}
	var rkf RawKeyFamily
	if err = jw.UnmarshalAgain(&rkf); err != nil {
		return
	}
	kf.BundlesForTesting = rkf.AllBundles
	kf.AllKIDs = make(map[keybase1.KID]bool)
	kf.PGPKeySets = make(map[keybase1.KID]*PGPKeySet)
	kf.SingleKeys = make(map[keybase1.KID]GenericKey)
	for i, bundle := range rkf.AllBundles {
		newKey, w, err := ParseGenericKey(bundle)
		if err != nil {
			g.Log.Notice("Failed to parse public key at position %d", i)
			g.Log.Debug("Key parsing error: %s", err)
			g.Log.Debug("Full key dump follows")
			g.Log.Debug(bundle)
			continue
		}
		w.Warn(g)
		kid := newKey.GetKID()
		if pgp, isPGP := newKey.(*PGPKeyBundle); isPGP {
			ks, ok := kf.PGPKeySets[kid]
			if !ok {
				ks = &PGPKeySet{NewContextified(g), nil, make(map[string]*PGPKeyBundle)}
				kf.PGPKeySets[kid] = ks
				fp := pgp.GetFingerprint()
				kf.pgp2kid[fp] = kid
				kf.kid2pgp[kid] = fp
			}
			ks.addKey(pgp)
		} else {
			kf.SingleKeys[kid] = newKey
		}
		kf.AllKIDs[kid] = true
	}
	ret = &kf
	return
}
func (ckf ComputedKeyFamily) FindKeyWithKIDUnsafe(kid keybase1.KID) (GenericKey, error) {
	if key, ok := ckf.kf.SingleKeys[kid]; ok {
		return key, nil
	}
	if ks, ok := ckf.kf.PGPKeySets[kid]; ok {
		if ckf.cki != nil {
			if cki, found := ckf.cki.Infos[kid]; found && cki.ActivePGPHash != "" {
				if key, ok := ks.KeysByHash[cki.ActivePGPHash]; ok {
					return key, nil
				}
				return nil, NoKeyError{fmt.Sprintf("Sigchain specified that KID %s is a PGP key with hash %s but no version of the key with that hash was found", kid, cki.ActivePGPHash)}
			}
		}
		return ks.PermissivelyMergedKey, nil
	}
	return nil, KeyFamilyError{fmt.Sprintf("No key found for %s", kid)}
}
func (ckf ComputedKeyFamily) getCkiIfActiveAtTime(kid keybase1.KID, t time.Time) (ret *ComputedKeyInfo, err error) {
	unixTime := t.Unix()
	if ki := ckf.cki.Infos[kid]; ki == nil {
		err = NoKeyError{fmt.Sprintf("The key '%s' wasn't found", kid)}
	} else if ki.Status != KeyUncancelled {
		err = KeyRevokedError{fmt.Sprintf("The key '%s' is no longer active", kid)}
	} else if ki.ETime > 0 && unixTime > ki.ETime {
		formatStr := "Mon Jan 2 15:04:05 -0700 MST 2006"
		ckf.G().Log.Warning("Checking status of key %s\n    with respect to time [%s],\n    found it had expired at [%s].",
			kid, t.Format(formatStr), time.Unix(ki.ETime, 0).Format(formatStr))
		err = KeyExpiredError{fmt.Sprintf("The key '%s' expired at %s", kid, time.Unix(ki.ETime, 0))}
	} else {
		ret = ki
	}
	return
}
func (ckf ComputedKeyFamily) getCkiIfActiveNow(kid keybase1.KID) (ret *ComputedKeyInfo, err error) {
	return ckf.getCkiIfActiveAtTime(kid, time.Now())
}
func (ckf ComputedKeyFamily) FindActiveSibkey(kid keybase1.KID) (key GenericKey, cki ComputedKeyInfo, err error) {
	return ckf.FindActiveSibkeyAtTime(kid, time.Now())
}