Add RootMetadataBuilder to simplify making RootMetadata
diff --git a/src/client.rs b/src/client.rs
index b596472..67c62cf 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -743,10 +743,9 @@
 #[cfg(test)]
 mod test {
     use super::*;
-    use chrono::prelude::*;
     use crypto::{PrivateKey, SignatureScheme};
     use interchange::Json;
-    use metadata::{MetadataPath, MetadataVersion, RoleDefinition, RootMetadata, SignedMetadata};
+    use metadata::{MetadataPath, MetadataVersion, RootMetadataBuilder};
     use repository::EphemeralRepository;
 
     lazy_static! {
@@ -768,18 +767,14 @@
     #[test]
     fn root_chain_update() {
         let repo = EphemeralRepository::new();
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, _> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .version(1)
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[0].public().clone())
+            .targets_key(KEYS[0].public().clone())
+            .timestamp_key(KEYS[0].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         repo.store_metadata(
             &MetadataPath::from_role(&Role::Root),
@@ -787,18 +782,14 @@
             &root,
         ).unwrap();
 
-        let root = RootMetadata::new(
-            2,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[1].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-        ).unwrap();
-        let mut root: SignedMetadata<Json, _> =
-            SignedMetadata::new(root, &KEYS[1]).unwrap();
+        let mut root = RootMetadataBuilder::new()
+            .version(2)
+            .root_key(KEYS[1].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[1].public().clone())
+            .timestamp_key(KEYS[1].public().clone())
+            .signed::<Json>(&KEYS[1])
+            .unwrap();
 
         root.add_signature(&KEYS[0]).unwrap();
 
@@ -808,18 +799,14 @@
             &root,
         ).unwrap();
 
-        let root = RootMetadata::new(
-            3,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[2].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-        ).unwrap();
-        let mut root: SignedMetadata<Json, _> =
-            SignedMetadata::new(root, &KEYS[2]).unwrap();
+        let mut root = RootMetadataBuilder::new()
+            .version(3)
+            .root_key(KEYS[2].public().clone())
+            .snapshot_key(KEYS[2].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[2].public().clone())
+            .signed::<Json>(&KEYS[2])
+            .unwrap();
 
         root.add_signature(&KEYS[1]).unwrap();
 
diff --git a/src/metadata.rs b/src/metadata.rs
index 4854ba7..99315c5 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -1,13 +1,12 @@
 //! TUF metadata.
 
 use chrono::offset::Utc;
-use chrono::DateTime;
+use chrono::{DateTime, Duration};
 use serde::de::{Deserialize, DeserializeOwned, Deserializer, Error as DeserializeError};
 use serde::ser::{Error as SerializeError, Serialize, Serializer};
 use std::collections::{HashMap, HashSet};
 use std::fmt::{self, Debug, Display};
 use std::io::Read;
-use std::iter::FromIterator;
 use std::marker::PhantomData;
 
 use crypto::{self, HashAlgorithm, HashValue, KeyId, PrivateKey, PublicKey, Signature};
@@ -499,6 +498,173 @@
     }
 }
 
+/// Helper to construct `RootMetadata`.
+pub struct RootMetadataBuilder {
+    version: u32,
+    expires: DateTime<Utc>,
+    consistent_snapshot: bool,
+    keys: HashMap<KeyId, PublicKey>,
+    root_threshold: u32,
+    root_key_ids: HashSet<KeyId>,
+    snapshot_threshold: u32,
+    snapshot_key_ids: HashSet<KeyId>,
+    targets_threshold: u32,
+    targets_key_ids: HashSet<KeyId>,
+    timestamp_threshold: u32,
+    timestamp_key_ids: HashSet<KeyId>,
+}
+
+impl RootMetadataBuilder {
+    /// Create a new `RootMetadataBuilder`. It defaults to:
+    ///
+    /// * version: 1,
+    /// * expires: 365 days from the current time.
+    /// * consistent snapshot: false
+    /// * role thresholds: 1
+    pub fn new() -> Self {
+        RootMetadataBuilder {
+            version: 1,
+            expires: Utc::now() + Duration::days(365),
+            consistent_snapshot: false,
+            keys: HashMap::new(),
+            root_threshold: 1,
+            root_key_ids: HashSet::new(),
+            snapshot_threshold: 1,
+            snapshot_key_ids: HashSet::new(),
+            targets_threshold: 1,
+            targets_key_ids: HashSet::new(),
+            timestamp_threshold: 1,
+            timestamp_key_ids: HashSet::new(),
+        }
+    }
+
+    /// Set the version number for this metadata.
+    pub fn version(mut self, version: u32) -> Self {
+        self.version = version;
+        self
+    }
+
+    /// Set the time this metadata expires.
+    pub fn expires(mut self, expires: DateTime<Utc>) -> Self {
+        self.expires = expires;
+        self
+    }
+
+    /// Set this metadata to have a consistent snapshot.
+    pub fn consistent_snapshot(mut self, consistent_snapshot: bool) -> Self {
+        self.consistent_snapshot = consistent_snapshot;
+        self
+    }
+
+    /// Set the root threshold.
+    pub fn root_threshold(mut self, threshold: u32) -> Self {
+        self.root_threshold = threshold;
+        self
+    }
+
+    /// Add a root public key.
+    pub fn root_key(mut self, public_key: PublicKey) -> Self {
+        let key_id = public_key.key_id().clone();
+        self.keys.insert(key_id.clone(), public_key);
+        self.root_key_ids.insert(key_id);
+        self
+    }
+
+    /// Set the snapshot threshold.
+    pub fn snapshot_threshold(mut self, threshold: u32) -> Self {
+        self.snapshot_threshold = threshold;
+        self
+    }
+
+    /// Add a snapshot public key.
+    pub fn snapshot_key(mut self, public_key: PublicKey) -> Self {
+        let key_id = public_key.key_id().clone();
+        self.keys.insert(key_id.clone(), public_key);
+        self.snapshot_key_ids.insert(key_id);
+        self
+    }
+
+    /// Set the targets threshold.
+    pub fn targets_threshold(mut self, threshold: u32) -> Self {
+        self.targets_threshold = threshold;
+        self
+    }
+
+    /// Add a targets public key.
+    pub fn targets_key(mut self, public_key: PublicKey) -> Self {
+        let key_id = public_key.key_id().clone();
+        self.keys.insert(key_id.clone(), public_key);
+        self.targets_key_ids.insert(key_id);
+        self
+    }
+
+    /// Set the timestamp threshold.
+    pub fn timestamp_threshold(mut self, threshold: u32) -> Self {
+        self.timestamp_threshold = threshold;
+        self
+    }
+
+    /// Add a timestamp public key.
+    pub fn timestamp_key(mut self, public_key: PublicKey) -> Self {
+        let key_id = public_key.key_id().clone();
+        self.keys.insert(key_id.clone(), public_key);
+        self.timestamp_key_ids.insert(key_id);
+        self
+    }
+
+    /// Construct a new `RootMetadata`.
+    pub fn build(self) -> Result<RootMetadata> {
+        RootMetadata::new(
+            self.version,
+            self.expires,
+            self.consistent_snapshot,
+            self.keys,
+            RoleDefinition::new(
+                self.root_threshold,
+                self.root_key_ids,
+            )?,
+            RoleDefinition::new(
+                self.snapshot_threshold,
+                self.snapshot_key_ids,
+            )?,
+            RoleDefinition::new(
+                self.targets_threshold,
+                self.targets_key_ids,
+            )?,
+            RoleDefinition::new(
+                self.timestamp_threshold,
+                self.timestamp_key_ids,
+            )?,
+        )
+    }
+
+    /// Construct a new `SignedMetadata<D, RootMetadata>`.
+    pub fn signed<D>(self, private_key: &PrivateKey) -> Result<SignedMetadata<D, RootMetadata>>
+        where D: DataInterchange,
+    {
+        Ok(SignedMetadata::new(self.build()?, private_key)?)
+    }
+}
+
+impl From<RootMetadata> for RootMetadataBuilder {
+    fn from(metadata: RootMetadata) -> Self {
+        RootMetadataBuilder {
+            version: metadata.version,
+            expires: metadata.expires,
+            consistent_snapshot: metadata.consistent_snapshot,
+            keys: metadata.keys,
+            root_threshold: metadata.root.threshold,
+            root_key_ids: metadata.root.key_ids,
+            snapshot_threshold: metadata.snapshot.threshold,
+            snapshot_key_ids: metadata.snapshot.key_ids,
+            targets_threshold: metadata.targets.threshold,
+            targets_key_ids: metadata.targets.key_ids,
+            timestamp_threshold: metadata.timestamp.threshold,
+            timestamp_key_ids: metadata.timestamp.key_ids,
+        }
+    }
+}
+
 /// Metadata for the root role.
 #[derive(Debug, Clone, PartialEq)]
 pub struct RootMetadata {
@@ -518,7 +684,7 @@
         version: u32,
         expires: DateTime<Utc>,
         consistent_snapshot: bool,
-        mut keys: Vec<PublicKey>,
+        keys: HashMap<KeyId, PublicKey>,
         root: RoleDefinition,
         snapshot: RoleDefinition,
         targets: RoleDefinition,
@@ -531,13 +697,6 @@
             )));
         }
 
-        let keys_len = keys.len();
-        let keys = HashMap::from_iter(keys.drain(..).map(|k| (k.key_id().clone(), k)));
-
-        if keys.len() != keys_len {
-            return Err(Error::IllegalArgument("Cannot have duplicate keys".into()));
-        }
-
         Ok(RootMetadata {
             version,
             expires,
@@ -1604,29 +1763,14 @@
         let timestamp_key =
             PrivateKey::from_pkcs8(ED25519_4_PK8, SignatureScheme::Ed25519).unwrap();
 
-        let keys = vec![
-            root_key.public().clone(),
-            snapshot_key.public().clone(),
-            targets_key.public().clone(),
-            timestamp_key.public().clone(),
-        ];
-
-        let root_def = RoleDefinition::new(1, hashset!(root_key.key_id().clone())).unwrap();
-        let snapshot_def = RoleDefinition::new(1, hashset!(snapshot_key.key_id().clone())).unwrap();
-        let targets_def = RoleDefinition::new(1, hashset!(targets_key.key_id().clone())).unwrap();
-        let timestamp_def =
-            RoleDefinition::new(1, hashset!(timestamp_key.key_id().clone())).unwrap();
-
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2017, 1, 1).and_hms(0, 0, 0),
-            false,
-            keys,
-            root_def,
-            snapshot_def,
-            targets_def,
-            timestamp_def,
-        ).unwrap();
+        let root = RootMetadataBuilder::new()
+            .expires(Utc.ymd(2017, 1, 1).and_hms(0, 0, 0))
+            .root_key(root_key.public().clone())
+            .snapshot_key(snapshot_key.public().clone())
+            .targets_key(targets_key.public().clone())
+            .timestamp_key(timestamp_key.public().clone())
+            .build()
+            .unwrap();
 
         let jsn = json!({
             "type": "root",
@@ -1884,7 +2028,7 @@
         });
 
         let encoded = json::to_value(&signed).unwrap();
-        assert_eq!(encoded, jsn);
+        assert_eq!(encoded, jsn, "{:#?} != {:#?}", encoded, jsn);
         let decoded: SignedMetadata<Json, SnapshotMetadata> = json::from_value(encoded).unwrap();
         assert_eq!(decoded, signed);
     }
@@ -1913,73 +2057,25 @@
     // TODO test for mismatched ed25519/rsa keys/schemes
 
     fn make_root() -> json::Value {
-        let root_def = RoleDefinition::new(
-            1,
-            hashset!(
-                PrivateKey::from_pkcs8(ED25519_1_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .key_id()
-                    .clone()
-            ),
-        ).unwrap();
+        let root_key = PrivateKey::from_pkcs8(ED25519_1_PK8, SignatureScheme::Ed25519)
+            .unwrap();
+        let snapshot_key = PrivateKey::from_pkcs8(ED25519_2_PK8, SignatureScheme::Ed25519)
+            .unwrap();
+        let targets_key = PrivateKey::from_pkcs8(ED25519_3_PK8, SignatureScheme::Ed25519)
+            .unwrap();
+        let timestamp_key = PrivateKey::from_pkcs8(ED25519_4_PK8, SignatureScheme::Ed25519)
+            .unwrap();
 
-        let snapshot_def = RoleDefinition::new(
-            1,
-            hashset!(
-                PrivateKey::from_pkcs8(ED25519_2_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .key_id()
-                    .clone()
-            ),
-        ).unwrap();
-
-        let targets_def = RoleDefinition::new(
-            1,
-            hashset!(
-                PrivateKey::from_pkcs8(ED25519_3_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .key_id()
-                    .clone()
-            ),
-        ).unwrap();
-
-        let timestamp_def = RoleDefinition::new(
-            1,
-            hashset!(
-                PrivateKey::from_pkcs8(ED25519_4_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .key_id()
-                    .clone()
-            ),
-        ).unwrap();
-
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                PrivateKey::from_pkcs8(ED25519_1_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .public()
-                    .clone(),
-                PrivateKey::from_pkcs8(ED25519_2_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .public()
-                    .clone(),
-                PrivateKey::from_pkcs8(ED25519_3_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .public()
-                    .clone(),
-                PrivateKey::from_pkcs8(ED25519_4_PK8, SignatureScheme::Ed25519)
-                    .unwrap()
-                    .public()
-                    .clone(),
-            ],
-            root_def,
-            snapshot_def,
-            targets_def,
-            timestamp_def,
-        ).unwrap();
+        let root = RootMetadataBuilder::new()
+            .expires(Utc.ymd(2038, 1, 1).and_hms(0, 0, 0))
+            .root_key(
+                root_key.public().clone()
+            )
+            .snapshot_key(snapshot_key.public().clone())
+            .targets_key(targets_key.public().clone())
+            .timestamp_key(timestamp_key.public().clone())
+            .build()
+            .unwrap();
 
         json::to_value(&root).unwrap()
     }
diff --git a/src/shims.rs b/src/shims.rs
index 324b2f9..890c0b8 100644
--- a/src/shims.rs
+++ b/src/shims.rs
@@ -2,6 +2,7 @@
 use chrono::prelude::*;
 use data_encoding::BASE64URL;
 use std::collections::{HashMap, HashSet};
+use std::iter::FromIterator;
 
 use crypto;
 use error::Error;
@@ -60,7 +61,7 @@
         })
     }
 
-    pub fn try_into(self) -> Result<metadata::RootMetadata> {
+    pub fn try_into(mut self) -> Result<metadata::RootMetadata> {
         if self.typ != metadata::Role::Root {
             return Err(Error::Encoding(format!(
                 "Attempted to decode root metdata labeled as {:?}",
@@ -68,11 +69,18 @@
             )));
         }
 
+        let keys_len = self.keys.len();
+        let keys = HashMap::from_iter(self.keys.drain(..).map(|k| (k.key_id().clone(), k)));
+
+        if keys.len() != keys_len {
+            return Err(Error::IllegalArgument("Cannot have duplicate keys".into()));
+        }
+
         metadata::RootMetadata::new(
             self.version,
             parse_datetime(&self.expires)?,
             self.consistent_snapshot,
-            self.keys,
+            keys,
             self.root,
             self.snapshot,
             self.targets,
diff --git a/src/tuf.rs b/src/tuf.rs
index 5a2cf68..c6c7b5e 100644
--- a/src/tuf.rs
+++ b/src/tuf.rs
@@ -616,7 +616,7 @@
     use chrono::prelude::*;
     use crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
     use interchange::Json;
-    use metadata::{MetadataDescription, RoleDefinition};
+    use metadata::{MetadataDescription, RootMetadataBuilder};
 
     lazy_static! {
         static ref KEYS: Vec<PrivateKey> = {
@@ -637,69 +637,50 @@
     #[test]
     fn root_pinned_success() {
         let root_key = &KEYS[0];
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone()],
-            RoleDefinition::new(1, hashset!(root_key.key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &root_key).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[0].public().clone())
+            .targets_key(KEYS[0].public().clone())
+            .timestamp_key(KEYS[0].public().clone())
+            .signed::<Json>(&root_key)
+            .unwrap();
 
         assert!(Tuf::from_root_pinned(root, &[root_key.key_id().clone()]).is_ok());
     }
 
     #[test]
     fn root_pinned_failure() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[0].public().clone())
+            .targets_key(KEYS[0].public().clone())
+            .timestamp_key(KEYS[0].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         assert!(Tuf::from_root_pinned(root, &[KEYS[1].key_id().clone()]).is_err());
     }
 
     #[test]
     fn good_root_rotation() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[0].public().clone())
+            .targets_key(KEYS[0].public().clone())
+            .timestamp_key(KEYS[0].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
-        let root = RootMetadata::new(
-            2,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[1].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-        ).unwrap();
-        let mut root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[1]).unwrap();
+        let mut root = RootMetadataBuilder::new()
+            .version(2)
+            .root_key(KEYS[1].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[1].public().clone())
+            .timestamp_key(KEYS[1].public().clone())
+            .signed::<Json>(&KEYS[1])
+            .unwrap();
 
         // add the original key's signature to make it cross signed
         root.add_signature(&KEYS[0]).unwrap();
@@ -712,52 +693,36 @@
 
     #[test]
     fn no_cross_sign_root_rotation() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[0].public().clone())
+            .targets_key(KEYS[0].public().clone())
+            .timestamp_key(KEYS[0].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
-        let root = RootMetadata::new(
-            2,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            // include the old key to prevent short circuiting the verify logic
-            vec![KEYS[0].public().clone(), KEYS[1].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[1]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[1].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[1].public().clone())
+            .timestamp_key(KEYS[1].public().clone())
+            .signed::<Json>(&KEYS[1])
+            .unwrap();
 
         assert!(tuf.update_root(root).is_err());
     }
 
     #[test]
     fn good_timestamp_update() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone(), KEYS[1].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[1].public().clone())
+            .timestamp_key(KEYS[1].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -777,18 +742,13 @@
 
     #[test]
     fn bad_timestamp_update_wrong_key() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![KEYS[0].public().clone(), KEYS[1].public().clone()],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[1].public().clone())
+            .timestamp_key(KEYS[1].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -807,22 +767,13 @@
 
     #[test]
     fn good_snapshot_update() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                KEYS[0].public().clone(),
-                KEYS[1].public().clone(),
-                KEYS[2].public().clone(),
-            ],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[2].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -849,22 +800,13 @@
 
     #[test]
     fn bad_snapshot_update_wrong_key() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                KEYS[0].public().clone(),
-                KEYS[1].public().clone(),
-                KEYS[2].public().clone(),
-            ],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[2].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -888,22 +830,13 @@
 
     #[test]
     fn bad_snapshot_update_wrong_version() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                KEYS[0].public().clone(),
-                KEYS[1].public().clone(),
-                KEYS[2].public().clone(),
-            ],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[2].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -927,23 +860,13 @@
 
     #[test]
     fn good_targets_update() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                KEYS[0].public().clone(),
-                KEYS[1].public().clone(),
-                KEYS[2].public().clone(),
-                KEYS[3].public().clone(),
-            ],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[3].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, _> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[3].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -982,23 +905,13 @@
 
     #[test]
     fn bad_targets_update_wrong_key() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                KEYS[0].public().clone(),
-                KEYS[1].public().clone(),
-                KEYS[2].public().clone(),
-                KEYS[3].public().clone(),
-            ],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[3].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[3].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
@@ -1034,23 +947,13 @@
 
     #[test]
     fn bad_targets_update_wrong_version() {
-        let root = RootMetadata::new(
-            1,
-            Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-            false,
-            vec![
-                KEYS[0].public().clone(),
-                KEYS[1].public().clone(),
-                KEYS[2].public().clone(),
-                KEYS[3].public().clone(),
-            ],
-            RoleDefinition::new(1, hashset!(KEYS[0].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[1].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[2].key_id().clone())).unwrap(),
-            RoleDefinition::new(1, hashset!(KEYS[3].key_id().clone())).unwrap(),
-        ).unwrap();
-        let root: SignedMetadata<Json, RootMetadata> =
-            SignedMetadata::new(root, &KEYS[0]).unwrap();
+        let root = RootMetadataBuilder::new()
+            .root_key(KEYS[0].public().clone())
+            .snapshot_key(KEYS[1].public().clone())
+            .targets_key(KEYS[2].public().clone())
+            .timestamp_key(KEYS[3].public().clone())
+            .signed::<Json>(&KEYS[0])
+            .unwrap();
 
         let mut tuf = Tuf::from_root(root).unwrap();
 
diff --git a/tests/integration.rs b/tests/integration.rs
index 37e1ad1..f732a73 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -9,7 +9,7 @@
 use tuf::crypto::{HashAlgorithm, PrivateKey, SignatureScheme};
 use tuf::interchange::Json;
 use tuf::metadata::{
-    Delegation, Delegations, MetadataDescription, MetadataPath, RoleDefinition, RootMetadata,
+    Delegation, Delegations, MetadataDescription, MetadataPath, RootMetadataBuilder,
     SignedMetadata, SnapshotMetadata, TargetDescription, TargetsMetadata, TimestampMetadata,
     VirtualTargetPath,
 };
@@ -31,30 +31,14 @@
     let delegation_key = PrivateKey::from_pkcs8(ED25519_5_PK8, SignatureScheme::Ed25519).unwrap();
 
     //// build the root ////
-    let keys = vec![
-        root_key.public().clone(),
-        snapshot_key.public().clone(),
-        targets_key.public().clone(),
-        timestamp_key.public().clone(),
-    ];
 
-    let root_def = RoleDefinition::new(1, hashset!(root_key.key_id().clone())).unwrap();
-    let snapshot_def = RoleDefinition::new(1, hashset!(snapshot_key.key_id().clone())).unwrap();
-    let targets_def = RoleDefinition::new(1, hashset!(targets_key.key_id().clone())).unwrap();
-    let timestamp_def = RoleDefinition::new(1, hashset!(timestamp_key.key_id().clone())).unwrap();
-
-    let root = RootMetadata::new(
-        1,
-        Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-        false,
-        keys,
-        root_def,
-        snapshot_def,
-        targets_def,
-        timestamp_def,
-    ).unwrap();
-
-    let signed = SignedMetadata::<Json, _>::new(root, &root_key).unwrap();
+    let signed = RootMetadataBuilder::new()
+        .root_key(root_key.public().clone())
+        .snapshot_key(snapshot_key.public().clone())
+        .targets_key(targets_key.public().clone())
+        .timestamp_key(timestamp_key.public().clone())
+        .signed::<Json>(&root_key)
+        .unwrap();
 
     let mut tuf = Tuf::<Json>::from_root_pinned(signed, &[root_key.key_id().clone()]).unwrap();
 
@@ -142,30 +126,14 @@
     let delegation_b_key = PrivateKey::from_pkcs8(ED25519_6_PK8, SignatureScheme::Ed25519).unwrap();
 
     //// build the root ////
-    let keys = vec![
-        root_key.public().clone(),
-        snapshot_key.public().clone(),
-        targets_key.public().clone(),
-        timestamp_key.public().clone(),
-    ];
 
-    let root_def = RoleDefinition::new(1, hashset!(root_key.key_id().clone())).unwrap();
-    let snapshot_def = RoleDefinition::new(1, hashset!(snapshot_key.key_id().clone())).unwrap();
-    let targets_def = RoleDefinition::new(1, hashset!(targets_key.key_id().clone())).unwrap();
-    let timestamp_def = RoleDefinition::new(1, hashset!(timestamp_key.key_id().clone())).unwrap();
-
-    let root = RootMetadata::new(
-        1,
-        Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-        false,
-        keys,
-        root_def,
-        snapshot_def,
-        targets_def,
-        timestamp_def,
-    ).unwrap();
-
-    let signed = SignedMetadata::<Json, _>::new(root, &root_key).unwrap();
+    let signed = RootMetadataBuilder::new()
+        .root_key(root_key.public().clone())
+        .snapshot_key(snapshot_key.public().clone())
+        .targets_key(targets_key.public().clone())
+        .timestamp_key(timestamp_key.public().clone())
+        .signed::<Json>(&root_key)
+        .unwrap();
 
     let mut tuf = Tuf::<Json>::from_root_pinned(signed, &[root_key.key_id().clone()]).unwrap();
 
diff --git a/tests/simple_example.rs b/tests/simple_example.rs
index 1381958..f264d1b 100644
--- a/tests/simple_example.rs
+++ b/tests/simple_example.rs
@@ -9,9 +9,9 @@
 use tuf::crypto::{HashAlgorithm, KeyId, PrivateKey, SignatureScheme};
 use tuf::interchange::{DataInterchange, Json};
 use tuf::metadata::{
-    MetadataDescription, MetadataPath, MetadataVersion, RoleDefinition, RootMetadata,
-    SignedMetadata, SnapshotMetadata, TargetDescription, TargetPath, TargetsMetadata,
-    TimestampMetadata, VirtualTargetPath,
+    MetadataDescription, MetadataPath, MetadataVersion, RootMetadataBuilder, SignedMetadata,
+    SnapshotMetadata, TargetDescription, TargetPath, TargetsMetadata, TimestampMetadata,
+    VirtualTargetPath,
 };
 use tuf::repository::{EphemeralRepository, Repository};
 use tuf::Result;
@@ -84,30 +84,13 @@
 
     //// build the root ////
 
-    let keys = vec![
-        root_key.public().clone(),
-        snapshot_key.public().clone(),
-        targets_key.public().clone(),
-        timestamp_key.public().clone(),
-    ];
-
-    let root_def = RoleDefinition::new(1, hashset!(root_key.key_id().clone()))?;
-    let snapshot_def = RoleDefinition::new(1, hashset!(snapshot_key.key_id().clone()))?;
-    let targets_def = RoleDefinition::new(1, hashset!(targets_key.key_id().clone()))?;
-    let timestamp_def = RoleDefinition::new(1, hashset!(timestamp_key.key_id().clone()))?;
-
-    let root = RootMetadata::new(
-        1,
-        Utc.ymd(2038, 1, 1).and_hms(0, 0, 0),
-        false,
-        keys,
-        root_def,
-        snapshot_def,
-        targets_def,
-        timestamp_def,
-    )?;
-
-    let signed = SignedMetadata::<Json, _>::new(root, &root_key)?;
+    let signed = RootMetadataBuilder::new()
+        .root_key(root_key.public().clone())
+        .snapshot_key(snapshot_key.public().clone())
+        .targets_key(targets_key.public().clone())
+        .timestamp_key(timestamp_key.public().clone())
+        .signed::<Json>(&root_key)
+        .unwrap();
 
     remote.store_metadata(
         &MetadataPath::new("root".into())?,