Split signed package into sign and verify packages

- Merge key database package keys into package verify
- Use Verifiers to check key validity instead of hard-coding
  Ed25519.

Signed-off-by: Jonathan Rudenberg <jonathan@titanous.com>
diff --git a/client/client.go b/client/client.go
index 1e1de2e..acc0240 100644
--- a/client/client.go
+++ b/client/client.go
@@ -8,9 +8,8 @@
 	"io/ioutil"
 
 	"github.com/flynn/go-tuf/data"
-	"github.com/flynn/go-tuf/keys"
-	"github.com/flynn/go-tuf/signed"
 	"github.com/flynn/go-tuf/util"
+	"github.com/flynn/go-tuf/verify"
 )
 
 // LocalStore is local storage for downloaded top-level metadata.
@@ -69,7 +68,7 @@
 	localMeta map[string]json.RawMessage
 
 	// db is a key DB used for verifying metadata
-	db *keys.DB
+	db *verify.DB
 
 	// consistentSnapshot indicates whether the remote storage is using
 	// consistent snapshots (as specified in root.json)
@@ -97,7 +96,7 @@
 		return err
 	}
 
-	c.db = keys.NewDB()
+	c.db = verify.NewDB()
 	rootKeyIDs := make([]string, len(rootKeys))
 	for i, key := range rootKeys {
 		id := key.ID()
@@ -131,7 +130,7 @@
 func (c *Client) update(latestRoot bool) (data.Files, error) {
 	// Always start the update using local metadata
 	if err := c.getLocalMeta(); err != nil {
-		if _, ok := err.(signed.ErrExpired); ok {
+		if _, ok := err.(verify.ErrExpired); ok {
 			if !latestRoot {
 				return c.updateWithLatestRoot(nil)
 			}
@@ -140,7 +139,7 @@
 			// should not have continued the update
 			return nil, err
 		}
-		if latestRoot && err == signed.ErrRoleThreshold {
+		if latestRoot && err == verify.ErrRoleThreshold {
 			// Root was updated with new keys, so our local metadata is no
 			// longer validating. Read only the versions from the local metadata
 			// and re-download everything.
@@ -162,7 +161,7 @@
 	if err != nil {
 		// ErrRoleThreshold could indicate timestamp keys have been
 		// revoked, so retry with the latest root.json
-		if isDecodeFailedWithErr(err, signed.ErrRoleThreshold) && !latestRoot {
+		if isDecodeFailedWithErr(err, verify.ErrRoleThreshold) && !latestRoot {
 			return c.updateWithLatestRoot(nil)
 		}
 		return nil, err
@@ -189,7 +188,7 @@
 	if err != nil {
 		// ErrRoleThreshold could indicate snapshot keys have been
 		// revoked, so retry with the latest root.json
-		if isDecodeFailedWithErr(err, signed.ErrRoleThreshold) && !latestRoot {
+		if isDecodeFailedWithErr(err, verify.ErrRoleThreshold) && !latestRoot {
 			return c.updateWithLatestRoot(nil)
 		}
 		return nil, err
@@ -267,7 +266,7 @@
 		if err := json.Unmarshal(s.Signed, root); err != nil {
 			return err
 		}
-		c.db = keys.NewDB()
+		c.db = verify.NewDB()
 		for id, k := range root.Keys {
 			if err := c.db.AddKey(id, k); err != nil {
 				return err
@@ -278,7 +277,7 @@
 				return err
 			}
 		}
-		if err := signed.Verify(s, "root", 0, c.db); err != nil {
+		if err := c.db.Verify(s, "root", 0); err != nil {
 			return err
 		}
 		c.consistentSnapshot = root.ConsistentSnapshot
@@ -288,7 +287,7 @@
 
 	if snapshotJSON, ok := meta["snapshot.json"]; ok {
 		snapshot := &data.Snapshot{}
-		if err := signed.UnmarshalTrusted(snapshotJSON, snapshot, "snapshot", c.db); err != nil {
+		if err := verify.UnmarshalTrusted(snapshotJSON, snapshot, "snapshot", c.db); err != nil {
 			return err
 		}
 		c.snapshotVer = snapshot.Version
@@ -296,7 +295,7 @@
 
 	if targetsJSON, ok := meta["targets.json"]; ok {
 		targets := &data.Targets{}
-		if err := signed.UnmarshalTrusted(targetsJSON, targets, "targets", c.db); err != nil {
+		if err := verify.UnmarshalTrusted(targetsJSON, targets, "targets", c.db); err != nil {
 			return err
 		}
 		c.targetsVer = targets.Version
@@ -305,7 +304,7 @@
 
 	if timestampJSON, ok := meta["timestamp.json"]; ok {
 		timestamp := &data.Timestamp{}
-		if err := signed.UnmarshalTrusted(timestampJSON, timestamp, "timestamp", c.db); err != nil {
+		if err := verify.UnmarshalTrusted(timestampJSON, timestamp, "timestamp", c.db); err != nil {
 			return err
 		}
 		c.timestampVer = timestamp.Version
@@ -454,7 +453,7 @@
 // decodeRoot decodes and verifies root metadata.
 func (c *Client) decodeRoot(b json.RawMessage) error {
 	root := &data.Root{}
-	if err := signed.Unmarshal(b, root, "root", c.rootVer, c.db); err != nil {
+	if err := verify.Unmarshal(b, root, "root", c.rootVer, c.db); err != nil {
 		return ErrDecodeFailed{"root.json", err}
 	}
 	c.rootVer = root.Version
@@ -466,7 +465,7 @@
 // root and targets file meta.
 func (c *Client) decodeSnapshot(b json.RawMessage) (data.FileMeta, data.FileMeta, error) {
 	snapshot := &data.Snapshot{}
-	if err := signed.Unmarshal(b, snapshot, "snapshot", c.snapshotVer, c.db); err != nil {
+	if err := verify.Unmarshal(b, snapshot, "snapshot", c.snapshotVer, c.db); err != nil {
 		return data.FileMeta{}, data.FileMeta{}, ErrDecodeFailed{"snapshot.json", err}
 	}
 	c.snapshotVer = snapshot.Version
@@ -477,7 +476,7 @@
 // returns updated targets.
 func (c *Client) decodeTargets(b json.RawMessage) (data.Files, error) {
 	targets := &data.Targets{}
-	if err := signed.Unmarshal(b, targets, "targets", c.targetsVer, c.db); err != nil {
+	if err := verify.Unmarshal(b, targets, "targets", c.targetsVer, c.db); err != nil {
 		return nil, ErrDecodeFailed{"targets.json", err}
 	}
 	updatedTargets := make(data.Files)
@@ -498,7 +497,7 @@
 // new snapshot file meta.
 func (c *Client) decodeTimestamp(b json.RawMessage) (data.FileMeta, error) {
 	timestamp := &data.Timestamp{}
-	if err := signed.Unmarshal(b, timestamp, "timestamp", c.timestampVer, c.db); err != nil {
+	if err := verify.Unmarshal(b, timestamp, "timestamp", c.timestampVer, c.db); err != nil {
 		return data.FileMeta{}, ErrDecodeFailed{"timestamp.json", err}
 	}
 	c.timestampVer = timestamp.Version
diff --git a/client/client_test.go b/client/client_test.go
index 846fb84..d715ea7 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -12,9 +12,8 @@
 
 	"github.com/flynn/go-tuf"
 	"github.com/flynn/go-tuf/data"
-	"github.com/flynn/go-tuf/keys"
-	"github.com/flynn/go-tuf/signed"
 	"github.com/flynn/go-tuf/util"
+	"github.com/flynn/go-tuf/verify"
 	. "gopkg.in/check.v1"
 )
 
@@ -133,9 +132,9 @@
 // any metadata marked to expire at s.expiredTime will be expired (this avoids
 // the need to sleep in the tests).
 func (s *ClientSuite) withMetaExpired(f func()) {
-	e := signed.IsExpired
-	defer func() { signed.IsExpired = e }()
-	signed.IsExpired = func(t time.Time) bool {
+	e := verify.IsExpired
+	defer func() { verify.IsExpired = e }()
+	verify.IsExpired = func(t time.Time) bool {
 		return t.Unix() == s.expiredTime.Round(time.Second).Unix()
 	}
 	f()
@@ -220,7 +219,7 @@
 		c.Fatalf("expected err to have type ErrDecodeFailed, got %T", err)
 	}
 	c.Assert(decodeErr.File, Equals, file)
-	expiredErr, ok := decodeErr.Err.(signed.ErrExpired)
+	expiredErr, ok := decodeErr.Err.(verify.ErrExpired)
 	if !ok {
 		c.Fatalf("expected err.Err to have type signed.ErrExpired, got %T", err)
 	}
@@ -246,7 +245,7 @@
 	client := NewClient(MemoryLocalStore(), s.remote)
 
 	// check Init() returns keys.ErrInvalidThreshold with an invalid threshold
-	c.Assert(client.Init(s.rootKeys(c), 0), Equals, keys.ErrInvalidThreshold)
+	c.Assert(client.Init(s.rootKeys(c), 0), Equals, verify.ErrInvalidThreshold)
 
 	// check Init() returns signed.ErrRoleThreshold when not enough keys
 	c.Assert(client.Init(s.rootKeys(c), 2), Equals, ErrInsufficientKeys)
@@ -332,7 +331,7 @@
 	for name, id := range newKeyIDs {
 		key := client.db.GetKey(id)
 		c.Assert(key, NotNil)
-		c.Assert(key.ID, Equals, id)
+		c.Assert(key.ID(), Equals, id)
 		role := client.db.GetRole(name)
 		c.Assert(role, NotNil)
 		c.Assert(role.KeyIDs, DeepEquals, map[string]struct{}{id: {}})
@@ -385,7 +384,7 @@
 	c.Assert(client.db.GetKey(oldID), IsNil)
 	key := client.db.GetKey(newID)
 	c.Assert(key, NotNil)
-	c.Assert(key.ID, Equals, newID)
+	c.Assert(key.ID(), Equals, newID)
 	role := client.db.GetRole("timestamp")
 	c.Assert(role, NotNil)
 	c.Assert(role.KeyIDs, DeepEquals, map[string]struct{}{newID: {}})
@@ -419,7 +418,7 @@
 	c.Assert(client.db.GetKey(oldID), IsNil)
 	key := client.db.GetKey(newID)
 	c.Assert(key, NotNil)
-	c.Assert(key.ID, Equals, newID)
+	c.Assert(key.ID(), Equals, newID)
 	role := client.db.GetRole("snapshot")
 	c.Assert(role, NotNil)
 	c.Assert(role.KeyIDs, DeepEquals, map[string]struct{}{newID: {}})
@@ -456,7 +455,7 @@
 	c.Assert(client.db.GetKey(oldID), IsNil)
 	key := client.db.GetKey(newID)
 	c.Assert(key, NotNil)
-	c.Assert(key.ID, Equals, newID)
+	c.Assert(key.ID(), Equals, newID)
 	role := client.db.GetRole("targets")
 	c.Assert(role, NotNil)
 	c.Assert(role.KeyIDs, DeepEquals, map[string]struct{}{newID: {}})
@@ -498,7 +497,7 @@
 	s.syncLocal(c)
 	s.withMetaExpired(func() {
 		err := client.getLocalMeta()
-		if _, ok := err.(signed.ErrExpired); !ok {
+		if _, ok := err.(verify.ErrExpired); !ok {
 			c.Fatalf("expected err to have type signed.ErrExpired, got %T", err)
 		}
 		c.Assert(client.rootVer, Equals, version)
@@ -528,7 +527,7 @@
 	// restarts itself, thus successfully updating
 	s.withMetaExpired(func() {
 		err := client.getLocalMeta()
-		if _, ok := err.(signed.ErrExpired); !ok {
+		if _, ok := err.(verify.ErrExpired); !ok {
 			c.Fatalf("expected err to have type signed.ErrExpired, got %T", err)
 		}
 
@@ -602,7 +601,7 @@
 	// restarts itself, thus successfully updating
 	s.withMetaExpired(func() {
 		err := client.getLocalMeta()
-		c.Assert(err, FitsTypeOf, signed.ErrExpired{})
+		c.Assert(err, FitsTypeOf, verify.ErrExpired{})
 
 		_, err = client.Update()
 		c.Assert(err, IsNil)
@@ -674,7 +673,7 @@
 
 	// check update returns ErrLowVersion
 	_, err = client.Update()
-	c.Assert(err, DeepEquals, ErrDecodeFailed{"timestamp.json", signed.ErrLowVersion{version, client.timestampVer}})
+	c.Assert(err, DeepEquals, ErrDecodeFailed{"timestamp.json", verify.ErrLowVersion{version, client.timestampVer}})
 }
 
 func (s *ClientSuite) TestUpdateTamperedTargets(c *C) {
diff --git a/keys/db.go b/keys/db.go
deleted file mode 100644
index 7613d5c..0000000
--- a/keys/db.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// Package keys implements an in-memory public key database for TUF.
-package keys
-
-import (
-	"errors"
-
-	"github.com/flynn/go-tuf/data"
-	"github.com/flynn/go-tuf/signed"
-)
-
-var (
-	ErrWrongType        = errors.New("tuf: invalid key type")
-	ErrExists           = errors.New("tuf: key already in db")
-	ErrWrongID          = errors.New("tuf: key id mismatch")
-	ErrInvalidKey       = errors.New("tuf: invalid key")
-	ErrInvalidRole      = errors.New("tuf: invalid role")
-	ErrInvalidKeyID     = errors.New("tuf: invalid key id")
-	ErrInvalidThreshold = errors.New("tuf: invalid role threshold")
-)
-
-type Key struct {
-	ID     string
-	Type   string
-	Public []byte
-}
-
-func (k *Key) Serialize() *data.Key {
-	return &data.Key{
-		Type:  k.Type,
-		Value: data.KeyValue{Public: k.Public[:]},
-	}
-}
-
-type Role struct {
-	KeyIDs    map[string]struct{}
-	Threshold int
-}
-
-func (r *Role) ValidKey(id string) bool {
-	_, ok := r.KeyIDs[id]
-	return ok
-}
-
-type DB struct {
-	roles map[string]*Role
-	keys  map[string]*Key
-}
-
-func NewDB() *DB {
-	return &DB{
-		roles: make(map[string]*Role),
-		keys:  make(map[string]*Key),
-	}
-}
-
-func (db *DB) AddKey(id string, k *data.Key) error {
-	v, ok := signed.Verifiers[k.Type]
-	if !ok {
-		return nil
-	}
-	if id != k.ID() {
-		return ErrWrongID
-	}
-	if !v.ValidKey(k.Value.Public) {
-		return ErrInvalidKey
-	}
-
-	db.keys[id] = &Key{
-		ID:     k.ID(),
-		Type:   k.Type,
-		Public: k.Value.Public,
-	}
-
-	return nil
-}
-
-var validRoles = map[string]struct{}{
-	"root":      {},
-	"targets":   {},
-	"snapshot":  {},
-	"timestamp": {},
-}
-
-func ValidRole(name string) bool {
-	_, ok := validRoles[name]
-	return ok
-}
-
-func (db *DB) AddRole(name string, r *data.Role) error {
-	if !ValidRole(name) {
-		return ErrInvalidRole
-	}
-	if r.Threshold < 1 {
-		return ErrInvalidThreshold
-	}
-
-	role := &Role{
-		KeyIDs:    make(map[string]struct{}),
-		Threshold: r.Threshold,
-	}
-	for _, id := range r.KeyIDs {
-		if len(id) != data.KeyIDLength {
-			return ErrInvalidKeyID
-		}
-		role.KeyIDs[id] = struct{}{}
-	}
-
-	db.roles[name] = role
-	return nil
-}
-
-func (db *DB) GetKey(id string) *Key {
-	return db.keys[id]
-}
-
-func (db *DB) GetRole(name string) *Role {
-	return db.roles[name]
-}
diff --git a/local_store.go b/local_store.go
index 9da6734..98d69e7 100644
--- a/local_store.go
+++ b/local_store.go
@@ -11,7 +11,7 @@
 
 	"github.com/flynn/go-tuf/data"
 	"github.com/flynn/go-tuf/encrypted"
-	"github.com/flynn/go-tuf/signed"
+	"github.com/flynn/go-tuf/sign"
 	"github.com/flynn/go-tuf/util"
 )
 
@@ -22,14 +22,14 @@
 	return &memoryStore{
 		meta:    meta,
 		files:   files,
-		signers: make(map[string][]signed.Signer),
+		signers: make(map[string][]sign.Signer),
 	}
 }
 
 type memoryStore struct {
 	meta    map[string]json.RawMessage
 	files   map[string][]byte
-	signers map[string][]signed.Signer
+	signers map[string][]sign.Signer
 }
 
 func (m *memoryStore) GetMeta() (map[string]json.RawMessage, error) {
@@ -67,11 +67,11 @@
 	return nil
 }
 
-func (m *memoryStore) GetSigningKeys(role string) ([]signed.Signer, error) {
+func (m *memoryStore) GetSigningKeys(role string) ([]sign.Signer, error) {
 	return m.signers[role], nil
 }
 
-func (m *memoryStore) SavePrivateKey(role string, key *signed.PrivateKey) error {
+func (m *memoryStore) SavePrivateKey(role string, key *sign.PrivateKey) error {
 	m.signers[role] = append(m.signers[role], key.Signer())
 	return nil
 }
@@ -89,7 +89,7 @@
 	return &fileSystemStore{
 		dir:            dir,
 		passphraseFunc: p,
-		signers:        make(map[string][]signed.Signer),
+		signers:        make(map[string][]sign.Signer),
 	}
 }
 
@@ -98,7 +98,7 @@
 	passphraseFunc util.PassphraseFunc
 
 	// signers is a cache of persisted keys to avoid decrypting multiple times
-	signers map[string][]signed.Signer
+	signers map[string][]sign.Signer
 }
 
 func (f *fileSystemStore) repoDir() string {
@@ -295,7 +295,7 @@
 	return f.Clean()
 }
 
-func (f *fileSystemStore) GetSigningKeys(role string) ([]signed.Signer, error) {
+func (f *fileSystemStore) GetSigningKeys(role string) ([]sign.Signer, error) {
 	if keys, ok := f.signers[role]; ok {
 		return keys, nil
 	}
@@ -310,7 +310,7 @@
 	return f.signers[role], nil
 }
 
-func (f *fileSystemStore) SavePrivateKey(role string, key *signed.PrivateKey) error {
+func (f *fileSystemStore) SavePrivateKey(role string, key *sign.PrivateKey) error {
 	if err := f.createDirs(); err != nil {
 		return err
 	}
@@ -357,8 +357,8 @@
 	return nil
 }
 
-func (f *fileSystemStore) privateKeySigners(keys []*signed.PrivateKey) []signed.Signer {
-	res := make([]signed.Signer, len(keys))
+func (f *fileSystemStore) privateKeySigners(keys []*sign.PrivateKey) []sign.Signer {
+	res := make([]sign.Signer, len(keys))
 	for i, k := range keys {
 		res[i] = k.Signer()
 	}
@@ -367,7 +367,7 @@
 
 // loadKeys loads keys for the given role and returns them along with the
 // passphrase (if read) so that callers don't need to re-read it.
-func (f *fileSystemStore) loadKeys(role string) ([]*signed.PrivateKey, []byte, error) {
+func (f *fileSystemStore) loadKeys(role string) ([]*sign.PrivateKey, []byte, error) {
 	file, err := os.Open(f.keysPath(role))
 	if err != nil {
 		return nil, nil, err
@@ -379,7 +379,7 @@
 		return nil, nil, err
 	}
 
-	var keys []*signed.PrivateKey
+	var keys []*sign.PrivateKey
 	if !pk.Encrypted {
 		if err := json.Unmarshal(pk.Data, &keys); err != nil {
 			return nil, nil, err
diff --git a/repo.go b/repo.go
index aad9b02..9fcf53f 100644
--- a/repo.go
+++ b/repo.go
@@ -10,9 +10,9 @@
 	"time"
 
 	"github.com/flynn/go-tuf/data"
-	"github.com/flynn/go-tuf/keys"
-	"github.com/flynn/go-tuf/signed"
+	"github.com/flynn/go-tuf/sign"
 	"github.com/flynn/go-tuf/util"
+	"github.com/flynn/go-tuf/verify"
 )
 
 type CompressionType uint8
@@ -47,8 +47,8 @@
 	WalkStagedTargets(paths []string, targetsFn targetsWalkFunc) error
 
 	Commit(map[string]json.RawMessage, bool, map[string]data.Hashes) error
-	GetSigningKeys(string) ([]signed.Signer, error)
-	SavePrivateKey(string, *signed.PrivateKey) error
+	GetSigningKeys(string) ([]sign.Signer, error)
+	SavePrivateKey(string, *sign.PrivateKey) error
 	Clean() error
 }
 
@@ -82,8 +82,8 @@
 	return r.setMeta("root.json", root)
 }
 
-func (r *Repo) db() (*keys.DB, error) {
-	db := keys.NewDB()
+func (r *Repo) db() (*verify.DB, error) {
+	db := verify.NewDB()
 	root, err := r.root()
 	if err != nil {
 		return nil, err
@@ -170,7 +170,7 @@
 }
 
 func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) (string, error) {
-	if !keys.ValidRole(keyRole) {
+	if !verify.ValidRole(keyRole) {
 		return "", ErrInvalidRole{keyRole}
 	}
 
@@ -183,7 +183,7 @@
 		return "", err
 	}
 
-	key, err := signed.GenerateEd25519Key()
+	key, err := sign.GenerateEd25519Key()
 	if err != nil {
 		return "", err
 	}
@@ -235,7 +235,7 @@
 }
 
 func (r *Repo) RevokeKeyWithExpires(keyRole, id string, expires time.Time) error {
-	if !keys.ValidRole(keyRole) {
+	if !verify.ValidRole(keyRole) {
 		return ErrInvalidRole{keyRole}
 	}
 
@@ -282,7 +282,7 @@
 	if err != nil {
 		return err
 	}
-	s, err := signed.Marshal(meta, keys...)
+	s, err := sign.Marshal(meta, keys...)
 	if err != nil {
 		return err
 	}
@@ -296,7 +296,7 @@
 
 func (r *Repo) Sign(name string) error {
 	role := strings.TrimSuffix(name, ".json")
-	if !keys.ValidRole(role) {
+	if !verify.ValidRole(role) {
 		return ErrInvalidRole{role}
 	}
 
@@ -313,7 +313,7 @@
 		return ErrInsufficientKeys{name}
 	}
 	for _, k := range keys {
-		signed.Sign(s, k)
+		sign.Sign(s, k)
 	}
 
 	b, err := json.Marshal(s)
@@ -330,7 +330,7 @@
 // been revoked are omitted), except for the root role in which case all local
 // keys are returned (revoked root keys still need to sign new root metadata so
 // clients can verify the new root.json and update their keys db accordingly).
-func (r *Repo) getSigningKeys(name string) ([]signed.Signer, error) {
+func (r *Repo) getSigningKeys(name string) ([]sign.Signer, error) {
 	signingKeys, err := r.local.GetSigningKeys(name)
 	if err != nil {
 		return nil, err
@@ -349,7 +349,7 @@
 	if len(role.KeyIDs) == 0 {
 		return nil, nil
 	}
-	keys := make([]signed.Signer, 0, len(role.KeyIDs))
+	keys := make([]sign.Signer, 0, len(role.KeyIDs))
 	for _, key := range signingKeys {
 		if _, ok := role.KeyIDs[key.ID()]; ok {
 			keys = append(keys, key)
@@ -635,13 +635,13 @@
 	return r.local.Clean()
 }
 
-func (r *Repo) verifySignature(name string, db *keys.DB) error {
+func (r *Repo) verifySignature(name string, db *verify.DB) error {
 	s, err := r.signedMeta(name)
 	if err != nil {
 		return err
 	}
 	role := strings.TrimSuffix(name, ".json")
-	if err := signed.Verify(s, role, 0, db); err != nil {
+	if err := db.Verify(s, role, 0); err != nil {
 		return ErrInsufficientSignatures{name, err}
 	}
 	return nil
diff --git a/repo_test.go b/repo_test.go
index 420b368..8ca4540 100644
--- a/repo_test.go
+++ b/repo_test.go
@@ -12,8 +12,9 @@
 
 	"github.com/flynn/go-tuf/data"
 	"github.com/flynn/go-tuf/encrypted"
-	"github.com/flynn/go-tuf/signed"
+	"github.com/flynn/go-tuf/sign"
 	"github.com/flynn/go-tuf/util"
+	"github.com/flynn/go-tuf/verify"
 	"golang.org/x/crypto/ed25519"
 	. "gopkg.in/check.v1"
 )
@@ -163,7 +164,7 @@
 	c.Assert(err, IsNil)
 	rootKey := db.GetKey(keyID)
 	c.Assert(rootKey, NotNil)
-	c.Assert(rootKey.ID, Equals, keyID)
+	c.Assert(rootKey.ID(), Equals, keyID)
 	role := db.GetRole("root")
 	c.Assert(role.KeyIDs, DeepEquals, map[string]struct{}{keyID: {}})
 
@@ -177,8 +178,8 @@
 	rootKeys, err := r.RootKeys()
 	c.Assert(err, IsNil)
 	c.Assert(rootKeys, HasLen, 1)
-	c.Assert(rootKeys[0].ID(), Equals, rootKey.ID)
-	c.Assert(rootKeys[0].Value.Public, DeepEquals, rootKey.Serialize().Value.Public)
+	c.Assert(rootKeys[0].ID(), Equals, rootKey.ID())
+	c.Assert(rootKeys[0].Value.Public, DeepEquals, rootKey.Value.Public)
 
 	// generate two targets keys
 	genKey(c, r, "targets")
@@ -205,7 +206,7 @@
 		}
 		key := db.GetKey(id)
 		c.Assert(key, NotNil)
-		c.Assert(key.ID, Equals, id)
+		c.Assert(key.ID(), Equals, id)
 	}
 	role = db.GetRole("targets")
 	c.Assert(role.KeyIDs, DeepEquals, targetKeyIDs)
@@ -214,7 +215,7 @@
 	rootKeys, err = r.RootKeys()
 	c.Assert(err, IsNil)
 	c.Assert(rootKeys, HasLen, 1)
-	c.Assert(rootKeys[0].ID(), Equals, rootKey.ID)
+	c.Assert(rootKeys[0].ID(), Equals, rootKey.ID())
 
 	// check the keys were saved correctly
 	localKeys, err = local.GetSigningKeys("targets")
@@ -321,7 +322,7 @@
 	}
 
 	// signing with an available key generates a signature
-	key, err := signed.GenerateEd25519Key()
+	key, err := sign.GenerateEd25519Key()
 	c.Assert(err, IsNil)
 	c.Assert(local.SavePrivateKey("root", key), IsNil)
 	c.Assert(r.Sign("root.json"), IsNil)
@@ -332,7 +333,7 @@
 	checkSigIDs(key.PublicData().ID())
 
 	// signing with a new available key generates another signature
-	newKey, err := signed.GenerateEd25519Key()
+	newKey, err := sign.GenerateEd25519Key()
 	c.Assert(err, IsNil)
 	c.Assert(local.SavePrivateKey("root", newKey), IsNil)
 	c.Assert(r.Sign("root.json"), IsNil)
@@ -364,7 +365,7 @@
 
 	// commit with timestamp.json but no timestamp key
 	c.Assert(r.Timestamp(), IsNil)
-	c.Assert(r.Commit(), DeepEquals, ErrInsufficientSignatures{"timestamp.json", signed.ErrNoSignatures})
+	c.Assert(r.Commit(), DeepEquals, ErrInsufficientSignatures{"timestamp.json", verify.ErrNoSignatures})
 
 	// commit success
 	genKey(c, r, "timestamp")
@@ -761,13 +762,13 @@
 	passphrase := []byte("s3cr3t")
 	store := FileSystemStore(tmp.path, testPassphraseFunc(passphrase))
 
-	assertKeys := func(role string, enc bool, expected []*signed.PrivateKey) {
+	assertKeys := func(role string, enc bool, expected []*sign.PrivateKey) {
 		keysJSON := tmp.readFile("keys/" + role + ".json")
 		pk := &persistedKeys{}
 		c.Assert(json.Unmarshal(keysJSON, pk), IsNil)
 
 		// check the persisted keys are correct
-		var actual []*signed.PrivateKey
+		var actual []*sign.PrivateKey
 		if enc {
 			c.Assert(pk.Encrypted, Equals, true)
 			decrypted, err := encrypted.Decrypt(pk.Data, passphrase)
@@ -792,28 +793,28 @@
 	}
 
 	// save a key and check it gets encrypted
-	key, err := signed.GenerateEd25519Key()
+	key, err := sign.GenerateEd25519Key()
 	c.Assert(err, IsNil)
 	c.Assert(store.SavePrivateKey("root", key), IsNil)
-	assertKeys("root", true, []*signed.PrivateKey{key})
+	assertKeys("root", true, []*sign.PrivateKey{key})
 
 	// save another key and check it gets added to the existing keys
-	newKey, err := signed.GenerateEd25519Key()
+	newKey, err := sign.GenerateEd25519Key()
 	c.Assert(err, IsNil)
 	c.Assert(store.SavePrivateKey("root", newKey), IsNil)
-	assertKeys("root", true, []*signed.PrivateKey{key, newKey})
+	assertKeys("root", true, []*sign.PrivateKey{key, newKey})
 
 	// check saving a key to an encrypted file without a passphrase fails
 	insecureStore := FileSystemStore(tmp.path, nil)
-	key, err = signed.GenerateEd25519Key()
+	key, err = sign.GenerateEd25519Key()
 	c.Assert(err, IsNil)
 	c.Assert(insecureStore.SavePrivateKey("root", key), Equals, ErrPassphraseRequired{"root"})
 
 	// save a key to an insecure store and check it is not encrypted
-	key, err = signed.GenerateEd25519Key()
+	key, err = sign.GenerateEd25519Key()
 	c.Assert(err, IsNil)
 	c.Assert(insecureStore.SavePrivateKey("targets", key), IsNil)
-	assertKeys("targets", false, []*signed.PrivateKey{key})
+	assertKeys("targets", false, []*sign.PrivateKey{key})
 }
 
 func (RepoSuite) TestManageMultipleTargets(c *C) {
diff --git a/signed/keys.go b/sign/keys.go
similarity index 98%
rename from signed/keys.go
rename to sign/keys.go
index 7e4fd3a..8afd2ae 100644
--- a/signed/keys.go
+++ b/sign/keys.go
@@ -1,4 +1,4 @@
-package signed
+package sign
 
 import (
 	"crypto/rand"
diff --git a/signed/sign.go b/sign/sign.go
similarity index 98%
rename from signed/sign.go
rename to sign/sign.go
index 41dd20b..f135e04 100644
--- a/signed/sign.go
+++ b/sign/sign.go
@@ -1,4 +1,4 @@
-package signed
+package sign
 
 import (
 	"crypto"
diff --git a/signed/errors.go b/signed/errors.go
deleted file mode 100644
index 10bdfd6..0000000
--- a/signed/errors.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package signed
-
-import (
-	"fmt"
-	"time"
-)
-
-type ErrExpired struct {
-	Expired time.Time
-}
-
-func (e ErrExpired) Error() string {
-	return fmt.Sprintf("expired at %s", e.Expired)
-}
-
-type ErrLowVersion struct {
-	Actual  int
-	Current int
-}
-
-func (e ErrLowVersion) Error() string {
-	return fmt.Sprintf("version %d is lower than current version %d", e.Actual, e.Current)
-}
diff --git a/verify/db.go b/verify/db.go
new file mode 100644
index 0000000..b0c287d
--- /dev/null
+++ b/verify/db.go
@@ -0,0 +1,87 @@
+package verify
+
+import (
+	"github.com/flynn/go-tuf/data"
+)
+
+type Role struct {
+	KeyIDs    map[string]struct{}
+	Threshold int
+}
+
+func (r *Role) ValidKey(id string) bool {
+	_, ok := r.KeyIDs[id]
+	return ok
+}
+
+type DB struct {
+	roles map[string]*Role
+	keys  map[string]*data.Key
+}
+
+func NewDB() *DB {
+	return &DB{
+		roles: make(map[string]*Role),
+		keys:  make(map[string]*data.Key),
+	}
+}
+
+func (db *DB) AddKey(id string, k *data.Key) error {
+	v, ok := Verifiers[k.Type]
+	if !ok {
+		return nil
+	}
+	if id != k.ID() {
+		return ErrWrongID
+	}
+	if !v.ValidKey(k.Value.Public) {
+		return ErrInvalidKey
+	}
+
+	db.keys[id] = k
+
+	return nil
+}
+
+var validRoles = map[string]struct{}{
+	"root":      {},
+	"targets":   {},
+	"snapshot":  {},
+	"timestamp": {},
+}
+
+func ValidRole(name string) bool {
+	_, ok := validRoles[name]
+	return ok
+}
+
+func (db *DB) AddRole(name string, r *data.Role) error {
+	if !ValidRole(name) {
+		return ErrInvalidRole
+	}
+	if r.Threshold < 1 {
+		return ErrInvalidThreshold
+	}
+
+	role := &Role{
+		KeyIDs:    make(map[string]struct{}),
+		Threshold: r.Threshold,
+	}
+	for _, id := range r.KeyIDs {
+		if len(id) != data.KeyIDLength {
+			return ErrInvalidKeyID
+		}
+		role.KeyIDs[id] = struct{}{}
+	}
+
+	db.roles[name] = role
+	return nil
+}
+
+func (db *DB) GetKey(id string) *data.Key {
+	return db.keys[id]
+}
+
+func (db *DB) GetRole(name string) *Role {
+	return db.roles[name]
+}
diff --git a/verify/errors.go b/verify/errors.go
new file mode 100644
index 0000000..08ef217
--- /dev/null
+++ b/verify/errors.go
@@ -0,0 +1,40 @@
+package verify
+
+import (
+	"errors"
+	"fmt"
+	"time"
+)
+
+var (
+	ErrMissingKey       = errors.New("tuf: missing key")
+	ErrNoSignatures     = errors.New("tuf: data has no signatures")
+	ErrInvalid          = errors.New("tuf: signature verification failed")
+	ErrWrongMethod      = errors.New("tuf: invalid signature type")
+	ErrUnknownRole      = errors.New("tuf: unknown role")
+	ErrRoleThreshold    = errors.New("tuf: valid signatures did not meet threshold")
+	ErrWrongMetaType    = errors.New("tuf: meta file has wrong type")
+	ErrExists           = errors.New("tuf: key already in db")
+	ErrWrongID          = errors.New("tuf: key id mismatch")
+	ErrInvalidKey       = errors.New("tuf: invalid key")
+	ErrInvalidRole      = errors.New("tuf: invalid role")
+	ErrInvalidKeyID     = errors.New("tuf: invalid key id")
+	ErrInvalidThreshold = errors.New("tuf: invalid role threshold")
+)
+
+type ErrExpired struct {
+	Expired time.Time
+}
+
+func (e ErrExpired) Error() string {
+	return fmt.Sprintf("expired at %s", e.Expired)
+}
+
+type ErrLowVersion struct {
+	Actual  int
+	Current int
+}
+
+func (e ErrLowVersion) Error() string {
+	return fmt.Sprintf("version %d is lower than current version %d", e.Actual, e.Current)
+}
diff --git a/signed/verifiers.go b/verify/verifiers.go
similarity index 75%
rename from signed/verifiers.go
rename to verify/verifiers.go
index cb09345..ac9ce34 100644
--- a/signed/verifiers.go
+++ b/verify/verifiers.go
@@ -1,4 +1,4 @@
-package signed
+package verify
 
 import (
 	"github.com/flynn/go-tuf/data"
@@ -22,12 +22,6 @@
 	data.KeyTypeEd25519: ed25519Verifier{},
 }
 
-// RegisterVerifier provides a convenience function for init() functions
-// to register additional verifiers or replace existing ones.
-func RegisterVerifier(name string, v Verifier) {
-	Verifiers[name] = v
-}
-
 type ed25519Verifier struct{}
 
 func (ed25519Verifier) Verify(key, msg, sig []byte) error {
@@ -37,6 +31,6 @@
 	return nil
 }
 
-func (ed25519Verifier) ValidKey(k []byte) {
+func (ed25519Verifier) ValidKey(k []byte) bool {
 	return len(k) == ed25519.PublicKeySize
 }
diff --git a/signed/verify.go b/verify/verify.go
similarity index 66%
rename from signed/verify.go
rename to verify/verify.go
index 7a52aae..b0823c7 100644
--- a/signed/verify.go
+++ b/verify/verify.go
@@ -1,35 +1,23 @@
-package signed
+package verify
 
 import (
 	"encoding/json"
-	"errors"
 	"strings"
 	"time"
 
 	"github.com/flynn/go-tuf/data"
-	"github.com/flynn/go-tuf/keys"
 	"github.com/tent/canonical-json-go"
 	"golang.org/x/crypto/ed25519"
 )
 
-var (
-	ErrMissingKey    = errors.New("tuf: missing key")
-	ErrNoSignatures  = errors.New("tuf: data has no signatures")
-	ErrInvalid       = errors.New("tuf: signature verification failed")
-	ErrWrongMethod   = errors.New("tuf: invalid signature type")
-	ErrUnknownRole   = errors.New("tuf: unknown role")
-	ErrRoleThreshold = errors.New("tuf: valid signatures did not meet threshold")
-	ErrWrongType     = errors.New("tuf: meta file has wrong type")
-)
-
 type signedMeta struct {
 	Type    string    `json:"_type"`
 	Expires time.Time `json:"expires"`
 	Version int       `json:"version"`
 }
 
-func Verify(s *data.Signed, role string, minVersion int, db *keys.DB) error {
-	if err := VerifySignatures(s, role, db); err != nil {
+func (db *DB) Verify(s *data.Signed, role string, minVersion int) error {
+	if err := db.VerifySignatures(s, role); err != nil {
 		return err
 	}
 
@@ -38,7 +26,7 @@
 		return err
 	}
 	if strings.ToLower(sm.Type) != strings.ToLower(role) {
-		return ErrWrongType
+		return ErrWrongMetaType
 	}
 	if IsExpired(sm.Expires) {
 		return ErrExpired{sm.Expires}
@@ -54,7 +42,7 @@
 	return t.Sub(time.Now()) <= 0
 }
 
-func VerifySignatures(s *data.Signed, role string, db *keys.DB) error {
+func (db *DB) VerifySignatures(s *data.Signed, role string) error {
 	if len(s.Signatures) == 0 {
 		return ErrNoSignatures
 	}
@@ -92,7 +80,7 @@
 		}
 
 		copy(sigBytes[:], sig.Signature)
-		if err := Verifiers[sig.Method].Verify(key.Public[:], msg, sigBytes[:]); err != nil {
+		if err := Verifiers[sig.Method].Verify(key.Value.Public, msg, sigBytes[:]); err != nil {
 			return err
 		}
 		valid[sig.KeyID] = struct{}{}
@@ -104,23 +92,23 @@
 	return nil
 }
 
-func Unmarshal(b []byte, v interface{}, role string, minVersion int, db *keys.DB) error {
+func Unmarshal(b []byte, v interface{}, role string, minVersion int, db *DB) error {
 	s := &data.Signed{}
 	if err := json.Unmarshal(b, s); err != nil {
 		return err
 	}
-	if err := Verify(s, role, minVersion, db); err != nil {
+	if err := db.Verify(s, role, minVersion); err != nil {
 		return err
 	}
 	return json.Unmarshal(s.Signed, v)
 }
 
-func UnmarshalTrusted(b []byte, v interface{}, role string, db *keys.DB) error {
+func UnmarshalTrusted(b []byte, v interface{}, role string, db *DB) error {
 	s := &data.Signed{}
 	if err := json.Unmarshal(b, s); err != nil {
 		return err
 	}
-	if err := VerifySignatures(s, role, db); err != nil {
+	if err := db.VerifySignatures(s, role); err != nil {
 		return err
 	}
 	return json.Unmarshal(s.Signed, v)
diff --git a/signed/verify_test.go b/verify/verify_test.go
similarity index 85%
rename from signed/verify_test.go
rename to verify/verify_test.go
index 58a00dd..2e15dc0 100644
--- a/signed/verify_test.go
+++ b/verify/verify_test.go
@@ -1,11 +1,11 @@
-package signed
+package verify
 
 import (
 	"testing"
 	"time"
 
 	"github.com/flynn/go-tuf/data"
-	"github.com/flynn/go-tuf/keys"
+	"github.com/flynn/go-tuf/sign"
 	"golang.org/x/crypto/ed25519"
 
 	. "gopkg.in/check.v1"
@@ -76,8 +76,8 @@
 		{
 			name: "more than enough signatures",
 			mut: func(t *test) {
-				k, _ := GenerateEd25519Key()
-				Sign(t.s, k.Signer())
+				k, _ := sign.GenerateEd25519Key()
+				sign.Sign(t.s, k.Signer())
 				t.keys = append(t.keys, k.PublicData())
 				t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.PublicData().ID())
 			},
@@ -93,15 +93,15 @@
 		{
 			name: "unknown key",
 			mut: func(t *test) {
-				k, _ := GenerateEd25519Key()
-				Sign(t.s, k.Signer())
+				k, _ := sign.GenerateEd25519Key()
+				sign.Sign(t.s, k.Signer())
 			},
 		},
 		{
 			name: "unknown key below threshold",
 			mut: func(t *test) {
-				k, _ := GenerateEd25519Key()
-				Sign(t.s, k.Signer())
+				k, _ := sign.GenerateEd25519Key()
+				sign.Sign(t.s, k.Signer())
 				t.roles["root"].Threshold = 2
 			},
 			err: ErrRoleThreshold,
@@ -109,16 +109,16 @@
 		{
 			name: "unknown keys in db",
 			mut: func(t *test) {
-				k, _ := GenerateEd25519Key()
-				Sign(t.s, k.Signer())
+				k, _ := sign.GenerateEd25519Key()
+				sign.Sign(t.s, k.Signer())
 				t.keys = append(t.keys, k.PublicData())
 			},
 		},
 		{
 			name: "unknown keys in db below threshold",
 			mut: func(t *test) {
-				k, _ := GenerateEd25519Key()
-				Sign(t.s, k.Signer())
+				k, _ := sign.GenerateEd25519Key()
+				sign.Sign(t.s, k.Signer())
 				t.keys = append(t.keys, k.PublicData())
 				t.roles["root"].Threshold = 2
 			},
@@ -127,7 +127,7 @@
 		{
 			name: "wrong type",
 			typ:  "bar",
-			err:  ErrWrongType,
+			err:  ErrWrongMetaType,
 		},
 		{
 			name: "low version",
@@ -155,8 +155,8 @@
 			t.typ = t.role
 		}
 		if t.keys == nil && t.s == nil {
-			k, _ := GenerateEd25519Key()
-			t.s, _ = Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k.Signer())
+			k, _ := sign.GenerateEd25519Key()
+			t.s, _ = sign.Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k.Signer())
 			t.keys = []*data.Key{k.PublicData()}
 		}
 		if t.roles == nil {
@@ -171,7 +171,7 @@
 			t.mut(&t)
 		}
 
-		db := keys.NewDB()
+		db := NewDB()
 		for _, k := range t.keys {
 			err := db.AddKey(k.ID(), k)
 			c.Assert(err, IsNil)
@@ -181,7 +181,7 @@
 			c.Assert(err, IsNil)
 		}
 
-		err := Verify(t.s, t.role, minVer, db)
+		err := db.Verify(t.s, t.role, minVer)
 		if e, ok := t.err.(ErrExpired); ok {
 			assertErrExpired(c, err, e)
 		} else {