collapsed error types some
diff --git a/src/client.rs b/src/client.rs
index 5c5ed59..8313aff 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -132,13 +132,13 @@
             )?;
             if !tuf.update_root(signed)? {
                 error!("{}", err_msg);
-                return Err(Error::Generic(err_msg.into()));
+                return Err(Error::Programming(err_msg.into()));
             }
         }
 
         if !tuf.update_root(latest_root)? {
             error!("{}", err_msg);
-            return Err(Error::Generic(err_msg.into()));
+            return Err(Error::Programming(err_msg.into()));
         }
         Ok(true)
     }
diff --git a/src/crypto.rs b/src/crypto.rs
index 0e4b097..9d73fc9 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -106,7 +106,7 @@
             "ed25519" => Ok(SignatureScheme::Ed25519),
             "rsassa-pss-sha256" => Ok(SignatureScheme::RsaSsaPssSha256),
             "rsassa-pss-sha512" => Ok(SignatureScheme::RsaSsaPssSha512),
-            typ => Err(Error::UnsupportedSignatureScheme(typ.into())),
+            typ => Err(Error::Encoding(typ.into())),
         }
     }
 }
@@ -185,7 +185,7 @@
         match s {
             "ed25519" => Ok(KeyType::Ed25519),
             "rsa" => Ok(KeyType::Rsa),
-            typ => Err(Error::UnsupportedKeyType(typ.into())),
+            typ => Err(Error::Encoding(typ.into())),
         }
     }
 }
@@ -228,7 +228,7 @@
     /// Create a `PublicKey` from an Ed25519 `PublicKeyValue`.
     pub fn from_ed25519(value: PublicKeyValue) -> Result<Self> {
         if value.value().len() != 32 {
-            return Err(Error::Decode(
+            return Err(Error::Encoding(
                 "Ed25519 public key was not 32 bytes long".into(),
             ));
         }
diff --git a/src/error.rs b/src/error.rs
index 4d4840b..66c2079 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -15,81 +15,72 @@
 pub enum Error {
     /// The metadata had a bad signature.
     BadSignature,
-    /// There was a problem decoding the metadata.
-    Decode(String),
-    /// There was a problem encoding the metadata.
-    Encode(String),
+    /// There was a problem encoding or decoding.
+    Encoding(String),
     /// Metadata was expired.
     ExpiredMetadata(Role),
-    /// Generic catcher for all errors.
-    Generic(String),
     /// An illegal argument was passed into a function.
     IllegalArgument(String),
-    /// There was an IO error.
-    Io(String),
     /// The metadata was missing, so an operation could not be completed.
     MissingMetadata(Role),
     /// There were no available hash algorithms.
     NoSupportedHashAlgorithm,
     /// The metadata or target was not found.
     NotFound,
-    /// There was an internal `serde` error.
-    Serde(String),
-    /// The key format is not supported.
-    UnsupportedKeyFormat(String),
-    /// The key type is not supported.
-    UnsupportedKeyType(String),
-    /// The signature scheme is not supported.
-    UnsupportedSignatureScheme(String),
+    /// Opaque error type, to be interpreted similar to HTTP 500. Something went wrong, and you may
+    /// or may not be able to do anything about it.
+    Opaque(String),
+    /// There was a library internal error. These errors are *ALWAYS* bugs and should be reported.
+    Programming(String),
     /// The metadata or target failed to verify.
     VerificationFailure(String),
 }
 
 impl From<json::error::Error> for Error {
     fn from(err: json::error::Error) -> Error {
-        Error::Serde(format!("{:?}", err))
+        Error::Encoding(format!("JSON: {:?}", err))
     }
 }
 
 impl Error {
     /// Helper to include the path that causd the error for FS I/O errors.
     pub fn from_io(err: io::Error, path: &Path) -> Error {
-        Error::Io(format!("Path {:?} : {:?}", path, err))
+        Error::Opaque(format!("Path {:?} : {:?}", path, err))
     }
 }
 
 impl From<io::Error> for Error {
     fn from(err: io::Error) -> Error {
-        Error::Io(format!("{:?}", err))
+        Error::Opaque(format!("IO: {:?}", err))
     }
 }
 
 impl From<hyper::error::Error> for Error {
     fn from(err: hyper::error::Error) -> Error {
-        Error::Generic(format!("{:?}", err))
+        Error::Opaque(format!("Hyper: {:?}", err))
     }
 }
 
 impl From<hyper::error::ParseError> for Error {
     fn from(err: hyper::error::ParseError) -> Error {
-        Error::Generic(format!("{:?}", err))
+        Error::Opaque(format!("Hyper: {:?}", err))
     }
 }
 
 impl From<DecodeError> for Error {
     fn from(err: DecodeError) -> Error {
-        Error::Decode(format!("{:?}", err))
+        Error::Encoding(format!("{:?}", err))
     }
 }
 
 impl From<pem::Error> for Error {
     fn from(err: pem::Error) -> Error {
-        Error::Decode(format!("{:?}", err))
+        Error::Encoding(format!("{:?}", err))
     }
 }
 
 impl From<der::Error> for Error {
     fn from(_: der::Error) -> Error {
-        Error::Io("Error reading/writing DER".into())
+        Error::Opaque("Error reading/writing DER".into())
     }
 }
diff --git a/src/interchange/mod.rs b/src/interchange/mod.rs
index 42bbbd2..d8a2c50 100644
--- a/src/interchange/mod.rs
+++ b/src/interchange/mod.rs
@@ -59,7 +59,7 @@
     }
 
     fn canonicalize(raw_data: &Self::RawData) -> Result<Vec<u8>> {
-        cjson::canonicalize(raw_data).map_err(|e| Error::Generic(e))
+        cjson::canonicalize(raw_data).map_err(|e| Error::Opaque(e))
     }
 
     fn deserialize<T>(raw_data: &Self::RawData) -> Result<T>
diff --git a/src/repository.rs b/src/repository.rs
index 7b8a6a1..a155a33 100644
--- a/src/repository.rs
+++ b/src/repository.rs
@@ -111,13 +111,13 @@
                 let msg = "Hash calculated when no expected hash supplied. \
                            This is a programming error. Please report this as a bug.";
                 error!("{}", msg);
-                Err(Error::Generic(msg.into()))
+                Err(Error::Programming(msg.into()))
             }
             (None, Some(_)) => {
                 let msg = "No hash calculated when expected hash supplied. \
                            This is a programming error. Please report this as a bug.";
                 error!("{}", msg);
-                Err(Error::Generic(msg.into()))
+                Err(Error::Programming(msg.into()))
             }
             (Some(_), Some(_)) |
             (None, None) => Ok(()),
@@ -277,7 +277,7 @@
                 role
             )));
         }
-        Err(Error::Generic(
+        Err(Error::Opaque(
             "Http repo store root not implemented".to_string(),
         ))
     }
diff --git a/src/shims.rs b/src/shims.rs
index 14e3ce3..c334e8d 100644
--- a/src/shims.rs
+++ b/src/shims.rs
@@ -41,7 +41,7 @@
 
     pub fn try_into(mut self) -> Result<metadata::RootMetadata> {
         if self.typ != metadata::Role::Root {
-            return Err(Error::Decode(format!(
+            return Err(Error::Encoding(format!(
                 "Attempted to decode root metdata labeled as {:?}",
                 self.typ
             )));
@@ -67,19 +67,19 @@
         }
 
         let root = self.roles.remove(&metadata::Role::Root).ok_or_else(|| {
-            Error::Decode("Missing root role definition".into())
+            Error::Encoding("Missing root role definition".into())
         })?;
         let snapshot = self.roles.remove(&metadata::Role::Snapshot).ok_or_else(
             || {
-                Error::Decode("Missing snapshot role definition".into())
+                Error::Encoding("Missing snapshot role definition".into())
             },
         )?;
         let targets = self.roles.remove(&metadata::Role::Targets).ok_or_else(|| {
-            Error::Decode("Missing targets role definition".into())
+            Error::Encoding("Missing targets role definition".into())
         })?;
         let timestamp = self.roles.remove(&metadata::Role::Timestamp).ok_or_else(
             || {
-                Error::Decode("Missing timestamp role definition".into())
+                Error::Encoding("Missing timestamp role definition".into())
             },
         )?;
 
@@ -153,7 +153,7 @@
                         )
                     }
                     x => {
-                        return Err(Error::UnsupportedKeyFormat(
+                        return Err(Error::Encoding(
                             format!("PEM with bad tag: {}", x),
                         ))
                     }
@@ -191,7 +191,7 @@
     pub fn try_into(mut self) -> Result<metadata::RoleDefinition> {
         let vec_len = self.key_ids.len();
         if vec_len < 1 {
-            return Err(Error::Decode(
+            return Err(Error::Encoding(
                 "Role defined with no assoiciated key IDs.".into(),
             ));
         }
@@ -200,7 +200,7 @@
         let dupes = vec_len - key_ids.len();
 
         if dupes != 0 {
-            return Err(Error::Decode(format!("Found {} duplicate key IDs.", dupes)));
+            return Err(Error::Encoding(format!("Found {} duplicate key IDs.", dupes)));
         }
 
         Ok(metadata::RoleDefinition::new(self.threshold, key_ids)?)
@@ -228,7 +228,7 @@
 
     pub fn try_into(self) -> Result<metadata::TimestampMetadata> {
         if self.typ != metadata::Role::Timestamp {
-            return Err(Error::Decode(format!(
+            return Err(Error::Encoding(format!(
                 "Attempted to decode timestamp metdata labeled as {:?}",
                 self.typ
             )));
@@ -259,7 +259,7 @@
 
     pub fn try_into(self) -> Result<metadata::SnapshotMetadata> {
         if self.typ != metadata::Role::Snapshot {
-            return Err(Error::Decode(format!(
+            return Err(Error::Encoding(format!(
                 "Attempted to decode snapshot metdata labeled as {:?}",
                 self.typ
             )));
@@ -291,7 +291,7 @@
 
     pub fn try_into(self) -> Result<metadata::TargetsMetadata> {
         if self.typ != metadata::Role::Targets {
-            return Err(Error::Decode(format!(
+            return Err(Error::Encoding(format!(
                 "Attempted to decode targets metdata labeled as {:?}",
                 self.typ
             )));
diff --git a/src/util.rs b/src/util.rs
index 35ed9ff..865bcc9 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -16,7 +16,7 @@
 
     let url_path = percent_decode(url_path.as_bytes())
         .decode_utf8()
-        .map_err(|e| Error::Generic(format!("{}", e)))?
+        .map_err(|e| Error::Opaque(format!("{}", e)))?
         .into_owned();
 
     Ok(Path::new(&url_path).to_path_buf())
@@ -28,7 +28,7 @@
         let component = percent_decode(component.as_bytes())
             .decode_utf8()
             .map_err(|e| {
-                Error::Generic(format!("Path component not utf-8: {:?}", e))
+                Error::Opaque(format!("Path component not utf-8: {:?}", e))
             })?
             .into_owned();
         out.push(component);
diff --git a/tests/ed25519/ed25519-1.pk8 b/tests/ed25519/ed25519-1.pk8
new file mode 100644
index 0000000..4582000
--- /dev/null
+++ b/tests/ed25519/ed25519-1.pk8
Binary files differ