Repository: rust-bitcoin/rust-bitcoin
Pull request #4448 (2025-05-05 18:50:28)

bitcoin: remove torv2 support
This PR removes support to TorV2 since it's deprecated and no longer useful to have it.


Patch:
diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml
index adb7e9f4..f4c71f56 100644
--- a/.cargo/mutants.toml
+++ b/.cargo/mutants.toml
@@ -4,15 +4,12 @@ exclude_globs = [
     "units/src/amount/verification.rs" # kani tests
 ]
 exclude_re = [
-    "impl Arbitrary",
     "impl Debug",
-    "impl fmt::Debug",
+    "impl Arbitrary",
     "impl Display",
-    "impl fmt::Display",
     ".*Error",
     "deserialize", # Skip serde mutation tests
     "Iterator", # Mutating operations in an iterator can result in an infinite loop
-    "match arm", "match guard", # New addition in cargo-mutants 25.0.1 deletes match arms and replaces match guards even in excluded functions
 
     # ----------------------------------Crate-specific exclusions----------------------------------
     # Units
diff --git a/README.md b/README.md
index 1a287bda..5cfe2c98 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ trustworthiness of each of your dependencies, including this one.
 This library **must not** be used for consensus code (i.e. fully validating blockchain data). It
 technically supports doing this, but doing so is very ill-advised because there are many deviations,
 known and unknown, between this library and the Bitcoin Core reference implementation. In a
-consensus based cryptocurrency, such as Bitcoin, it is critical that all parties are using the same
+consensus based cryptocurrency such as Bitcoin it is critical that all parties are using the same
 rules to validate data, and this library is simply unable to implement the same rules as Core.
 
 Given the complexity of both C++ and Rust, it is unlikely that this will ever be fixed, and there
@@ -68,11 +68,11 @@ and to expand on existing docs would be extremely appreciated.
 
 Contributions are generally welcome. If you intend to make larger changes please discuss them in an
 issue before PRing them to avoid duplicate work and architectural mismatches. If you have any
-questions or ideas you want to discuss, please join us in
+questions or ideas you want to discuss please join us in
 [#bitcoin-rust](https://web.libera.chat/?channel=#bitcoin-rust) on
 [libera.chat](https://libera.chat).
 
-For more information, please see [`CONTRIBUTING.md`](./CONTRIBUTING.md).
+For more information please see [`CONTRIBUTING.md`](./CONTRIBUTING.md).
 
 ## Minimum Supported Rust Version (MSRV)
 
@@ -83,7 +83,7 @@ Use `Cargo-minimal.lock` to build the MSRV by copying to `Cargo.lock` and buildi
 ## External dependencies
 
 We integrate with a few external libraries, most notably `serde`. These
-are available via feature flags. To ensure compatibility and MSRV stability, we
+are available via feature flags. To ensure compatibility and MSRV stability we
 provide two lock files as a means of inspecting compatible versions:
 `Cargo-minimal.lock` containing minimal versions of dependencies and
 `Cargo-recent.lock` containing recent versions of dependencies tested in our CI.
@@ -152,8 +152,8 @@ developers, especially new contributors looking for something to work on, we do:
 - Mutation testing with [`cargo-mutants`](https://github.com/sourcefrog/cargo-mutants)
 - Code verification with [`Kani`](https://github.com/model-checking/kani)
 
-There are always more tests to write and more bugs to find. PRs are extremely welcomed.
-Please consider testing code as a first-class citizen. We definitely do take PRs
+There are always more tests to write and more bugs to find, contributions to our testing efforts
+extremely welcomed. Please consider testing code a first class citizen, we definitely do take PRs
 improving and cleaning up test code.
 
 ### Unit/Integration tests
@@ -178,7 +178,7 @@ We have started using [kani](https://github.com/model-checking/kani), install wi
 
 ## Pull Requests
 
-Every PR needs at least two reviews to get merged. During the review phase, maintainers and
+Every PR needs at least two reviews to get merged. During the review phase maintainers and
 contributors are likely to leave comments and request changes. Please try to address them, otherwise
 your PR might get closed without merging after a longer time of inactivity. If your PR isn't ready
 for review yet please mark it by prefixing the title with `WIP: `.
@@ -201,7 +201,7 @@ to your githooks folder or run `just githooks-install` to copy them all.
 
 Since the altcoin landscape includes projects which [frequently appear and disappear, and are poorly
 designed anyway](https://download.wpsoftware.net/bitcoin/alts.pdf) we do not support any altcoins.
-Supporting Bitcoin properly is already difficult enough, and we do not want to increase the
+Supporting Bitcoin properly is already difficult enough and we do not want to increase the
 maintenance burden and decrease API stability by adding support for other coins.
 
 Our code is public domain so by all means fork it and go wild :)
diff --git a/bitcoin/examples/bip32.rs b/bitcoin/examples/bip32.rs
index 7cde6c64..9df5ef67 100644
--- a/bitcoin/examples/bip32.rs
+++ b/bitcoin/examples/bip32.rs
@@ -33,12 +33,12 @@ fn main() {
     let secp = Secp256k1::preallocated_new(buf.as_mut_slice()).unwrap();
 
     // calculate root key from seed
-    let root = Xpriv::new_master(NetworkKind::Main, &seed);
+    let root = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
     println!("Root key: {}", root);
 
     // derive child xpub
     let path = "84h/0h/0h".parse::<DerivationPath>().unwrap();
-    let child = root.derive_xpriv(&secp, &path).expect("only deriving three steps");
+    let child = root.derive_xpriv(&secp, &path);
     println!("Child at {}: {}", path, child);
     let xpub = Xpub::from_xpriv(&secp, &child);
     println!("Public key at {}: {}", path, xpub);
diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs
index 21b9f6ca..ac5d84b4 100644
--- a/bitcoin/examples/ecdsa-psbt-simple.rs
+++ b/bitcoin/examples/ecdsa-psbt-simple.rs
@@ -62,12 +62,11 @@ fn get_external_address_xpriv<C: Signing>(
 ) -> Xpriv {
     let derivation_path =
         BIP84_DERIVATION_PATH.into_derivation_path().expect("valid derivation path");
-    let child_xpriv =
-        master_xpriv.derive_xpriv(secp, &derivation_path).expect("only deriving three steps");
+    let child_xpriv = master_xpriv.derive_xpriv(secp, &derivation_path);
     let external_index = ChildNumber::ZERO_NORMAL;
     let idx = ChildNumber::from_normal_idx(index).expect("valid index number");
 
-    child_xpriv.derive_xpriv(secp, &[external_index, idx]).expect("only deriving two more steps")
+    child_xpriv.derive_xpriv(secp, &[external_index, idx])
 }
 
 // Derive the internal address xpriv.
@@ -78,12 +77,11 @@ fn get_internal_address_xpriv<C: Signing>(
 ) -> Xpriv {
     let derivation_path =
         BIP84_DERIVATION_PATH.into_derivation_path().expect("valid derivation path");
-    let child_xpriv =
-        master_xpriv.derive_xpriv(secp, &derivation_path).expect("only deriving three steps");
+    let child_xpriv = master_xpriv.derive_xpriv(secp, &derivation_path);
     let internal_index = ChildNumber::ONE_NORMAL;
     let idx = ChildNumber::from_normal_idx(index).expect("valid index number");
 
-    child_xpriv.derive_xpriv(secp, &[internal_index, idx]).expect("only deriving two more steps")
+    child_xpriv.derive_xpriv(secp, &[internal_index, idx])
 }
 
 // The address to send to.
diff --git a/bitcoin/examples/ecdsa-psbt.rs b/bitcoin/examples/ecdsa-psbt.rs
index 1abdf675..85ffb878 100644
--- a/bitcoin/examples/ecdsa-psbt.rs
+++ b/bitcoin/examples/ecdsa-psbt.rs
@@ -118,12 +118,11 @@ fn new<C: Signing>(secp: &Secp256k1<C>, xpriv: &str) -> Result<ExportData> {
         // Hardened children require secret data to derive.
 
         let path = "84h/0h/0h".into_derivation_path()?;
-        let account_0_xpriv =
-            master_xpriv.derive_xpriv(secp, &path).expect("derivation path is short");
+        let account_0_xpriv = master_xpriv.derive_xpriv(secp, &path);
         let account_0_xpub = Xpub::from_xpriv(secp, &account_0_xpriv);
 
         let path = INPUT_UTXO_DERIVATION_PATH.into_derivation_path()?;
-        let input_xpriv = master_xpriv.derive_xpriv(secp, &path).expect("derivation path is short");
+        let input_xpriv = master_xpriv.derive_xpriv(secp, &path);
         let input_xpub = Xpub::from_xpriv(secp, &input_xpriv);
 
         let wallet = ColdStorage { master_xpriv, master_xpub };
diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs
index 2abb4d58..06a3fab1 100644
--- a/bitcoin/examples/sign-tx-taproot.rs
+++ b/bitcoin/examples/sign-tx-taproot.rs
@@ -71,7 +71,7 @@ fn main() {
     // Sign the sighash using the secp256k1 library (exported by rust-bitcoin).
     let tweaked: TweakedKeypair = keypair.tap_tweak(&secp, None);
     let msg = Message::from(sighash);
-    let signature = secp.sign_schnorr(msg.as_ref(), tweaked.as_keypair());
+    let signature = secp.sign_schnorr(msg.as_ref(), &tweaked.to_inner());
 
     // Update the witness stack.
     let signature = bitcoin::taproot::Signature { signature, sighash_type };
diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs
index d2ca8f9e..8181573a 100644
--- a/bitcoin/examples/taproot-psbt-simple.rs
+++ b/bitcoin/examples/taproot-psbt-simple.rs
@@ -60,12 +60,11 @@ fn get_external_address_xpriv<C: Signing>(
 ) -> Xpriv {
     let derivation_path =
         BIP86_DERIVATION_PATH.into_derivation_path().expect("valid derivation path");
-    let child_xpriv =
-        master_xpriv.derive_xpriv(secp, &derivation_path).expect("only deriving three steps");
+    let child_xpriv = master_xpriv.derive_xpriv(secp, &derivation_path);
     let external_index = ChildNumber::ZERO_NORMAL;
     let idx = ChildNumber::from_normal_idx(index).expect("valid index number");
 
-    child_xpriv.derive_xpriv(secp, &[external_index, idx]).expect("only deriving two more steps")
+    child_xpriv.derive_xpriv(secp, &[external_index, idx])
 }
 
 // Derive the internal address xpriv.
@@ -76,12 +75,11 @@ fn get_internal_address_xpriv<C: Signing>(
 ) -> Xpriv {
     let derivation_path =
         BIP86_DERIVATION_PATH.into_derivation_path().expect("valid derivation path");
-    let child_xpriv =
-        master_xpriv.derive_xpriv(secp, &derivation_path).expect("only deriving three steps");
+    let child_xpriv = master_xpriv.derive_xpriv(secp, &derivation_path);
     let internal_index = ChildNumber::ONE_NORMAL;
     let idx = ChildNumber::from_normal_idx(index).expect("valid index number");
 
-    child_xpriv.derive_xpriv(secp, &[internal_index, idx]).expect("only deriving two more steps")
+    child_xpriv.derive_xpriv(secp, &[internal_index, idx])
 }
 
 // Get the Taproot Key Origin.
diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs
index 75bb0b8b..ab8f8af4 100644
--- a/bitcoin/examples/taproot-psbt.rs
+++ b/bitcoin/examples/taproot-psbt.rs
@@ -299,7 +299,7 @@ fn generate_bip86_key_spend_tx(
                 .ok_or("missing Taproot key origin")?;
 
             let secret_key =
-                master_xpriv.derive_xpriv(secp, &derivation_path)?.to_private_key().inner;
+                master_xpriv.derive_xpriv(secp, &derivation_path).to_private_key().inner;
             sign_psbt_taproot(
                 secret_key,
                 input.tap_internal_key.unwrap(),
@@ -393,11 +393,8 @@ fn create_inheritance_funding_tx(
         // We use some other derivation path in this example for our inheritance protocol. The important thing is to ensure
         // that we use an unhardened path so we can make use of xpubs.
         let derivation_path = format!("101/1/0/0/{}", self.next).parse::<DerivationPath>()?;
-        let internal_keypair = self
-            .master_xpriv
-            .derive_xpriv(&self.secp, &derivation_path)
-            .expect("derivation path is short")
-            .to_keypair(&self.secp);
+        let internal_keypair =
+            self.master_xpriv.derive_xpriv(&self.secp, &derivation_path).to_keypair(&self.secp);
         let beneficiary_key =
             self.beneficiary_xpub.derive_xpub(&self.secp, &derivation_path)?.to_x_only_public_key();
 
@@ -489,7 +486,6 @@ fn refresh_tx(
             let new_internal_keypair = self
                 .master_xpriv
                 .derive_xpriv(&self.secp, &new_derivation_path)
-                .expect("derivation path is short")
                 .to_keypair(&self.secp);
             let beneficiary_key = self
                 .beneficiary_xpub
@@ -542,7 +538,6 @@ fn refresh_tx(
                 let secret_key = self
                     .master_xpriv
                     .derive_xpriv(&self.secp, &derivation_path)
-                    .expect("derivation path is short")
                     .to_private_key()
                     .inner;
                 sign_psbt_taproot(
@@ -665,11 +660,8 @@ fn spend_inheritance(
         for (x_only_pubkey, (leaf_hashes, (_, derivation_path))) in
             &psbt.inputs[0].tap_key_origins.clone()
         {
-            let secret_key = self
-                .master_xpriv
-                .derive_xpriv(&self.secp, &derivation_path)?
-                .to_private_key()
-                .inner;
+            let secret_key =
+                self.master_xpriv.derive_xpriv(&self.secp, &derivation_path).to_private_key().inner;
             for lh in leaf_hashes {
                 let sighash_type = TapSighashType::All;
                 let hash = SighashCache::new(&unsigned_tx).taproot_script_spend_signature_hash(
@@ -752,7 +744,7 @@ fn sign_psbt_taproot(
 ) {
     let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
     let keypair = match leaf_hash {
-        None => keypair.tap_tweak(secp, psbt_input.tap_merkle_root).to_keypair(),
+        None => keypair.tap_tweak(secp, psbt_input.tap_merkle_root).to_inner(),
         Some(_) => keypair, // no tweak for script spend
     };
 
diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs
index 12be7a31..7d20f58a 100644
--- a/bitcoin/src/bip32.rs
+++ b/bitcoin/src/bip32.rs
@@ -148,11 +148,11 @@ impl ChildNumber {
     /// [0, 2^31 - 1].
     ///
     /// [`Normal`]: #variant.Normal
-    pub fn from_normal_idx(index: u32) -> Result<Self, IndexOutOfRangeError> {
+    pub fn from_normal_idx(index: u32) -> Result<Self, Error> {
         if index & (1 << 31) == 0 {
             Ok(ChildNumber::Normal { index })
         } else {
-            Err(IndexOutOfRangeError { index })
+            Err(Error::InvalidChildNumber(index))
         }
     }
 
@@ -160,11 +160,11 @@ pub fn from_normal_idx(index: u32) -> Result<Self, IndexOutOfRangeError> {
     /// [0, 2^31 - 1].
     ///
     /// [`Hardened`]: #variant.Hardened
-    pub fn from_hardened_idx(index: u32) -> Result<Self, IndexOutOfRangeError> {
+    pub fn from_hardened_idx(index: u32) -> Result<Self, Error> {
         if index & (1 << 31) == 0 {
             Ok(ChildNumber::Hardened { index })
         } else {
-            Err(IndexOutOfRangeError { index })
+            Err(Error::InvalidChildNumber(index))
         }
     }
 
@@ -184,10 +184,7 @@ pub fn is_hardened(&self) -> bool {
     }
 
     /// Returns the child number that is a single increment from this one.
-    pub fn increment(self) -> Result<ChildNumber, IndexOutOfRangeError> {
-        // Bare addition in this function is okay, because we have an invariant that
-        // `index` is always within [0, 2^31 - 1]. FIXME this is not actually an
-        // invariant because the fields are public.
+    pub fn increment(self) -> Result<ChildNumber, Error> {
         match self {
             ChildNumber::Normal { index: idx } => ChildNumber::from_normal_idx(idx + 1),
             ChildNumber::Hardened { index: idx } => ChildNumber::from_hardened_idx(idx + 1),
@@ -228,18 +225,16 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl FromStr for ChildNumber {
-    type Err = ParseChildNumberError;
+    type Err = Error;
 
-    fn from_str(inp: &str) -> Result<Self, Self::Err> {
+    fn from_str(inp: &str) -> Result<ChildNumber, Error> {
         let is_hardened = inp.chars().last().map_or(false, |l| l == '\'' || l == 'h');
         Ok(if is_hardened {
             ChildNumber::from_hardened_idx(
-                inp[0..inp.len() - 1].parse().map_err(ParseChildNumberError::ParseInt)?,
-            )
-            .map_err(ParseChildNumberError::IndexOutOfRange)?
+                inp[0..inp.len() - 1].parse().map_err(|_| Error::InvalidChildNumberFormat)?,
+            )?
         } else {
-            ChildNumber::from_normal_idx(inp.parse().map_err(ParseChildNumberError::ParseInt)?)
-                .map_err(ParseChildNumberError::IndexOutOfRange)?
+            ChildNumber::from_normal_idx(inp.parse().map_err(|_| Error::InvalidChildNumberFormat)?)?
         })
     }
 }
@@ -272,7 +267,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 /// derivation path
 pub trait IntoDerivationPath {
     /// Converts a given type into a [`DerivationPath`] with possible error
-    fn into_derivation_path(self) -> Result<DerivationPath, ParseChildNumberError>;
+    fn into_derivation_path(self) -> Result<DerivationPath, Error>;
 }
 
 /// A BIP-32 derivation path.
@@ -300,17 +295,15 @@ impl<T> IntoDerivationPath for T
 where
     T: Into<DerivationPath>,
 {
-    fn into_derivation_path(self) -> Result<DerivationPath, ParseChildNumberError> {
-        Ok(self.into())
-    }
+    fn into_derivation_path(self) -> Result<DerivationPath, Error> { Ok(self.into()) }
 }
 
 impl IntoDerivationPath for String {
-    fn into_derivation_path(self) -> Result<DerivationPath, ParseChildNumberError> { self.parse() }
+    fn into_derivation_path(self) -> Result<DerivationPath, Error> { self.parse() }
 }
 
 impl IntoDerivationPath for &'_ str {
-    fn into_derivation_path(self) -> Result<DerivationPath, ParseChildNumberError> { self.parse() }
+    fn into_derivation_path(self) -> Result<DerivationPath, Error> { self.parse() }
 }
 
 impl From<Vec<ChildNumber>> for DerivationPath {
@@ -345,9 +338,9 @@ fn as_ref(&self) -> &[ChildNumber] { &self.0 }
 }
 
 impl FromStr for DerivationPath {
-    type Err = ParseChildNumberError;
+    type Err = Error;
 
-    fn from_str(path: &str) -> Result<Self, Self::Err> {
+    fn from_str(path: &str) -> Result<DerivationPath, Error> {
         if path.is_empty() || path == "m" || path == "m/" {
             return Ok(vec![].into());
         }
@@ -355,7 +348,7 @@ fn from_str(path: &str) -> Result<Self, Self::Err> {
         let path = path.strip_prefix("m/").unwrap_or(path);
 
         let parts = path.split('/');
-        let ret: Result<Vec<ChildNumber>, _> = parts.map(str::parse).collect();
+        let ret: Result<Vec<ChildNumber>, Error> = parts.map(str::parse).collect();
         Ok(DerivationPath(ret?))
     }
 }
@@ -503,15 +496,27 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self,
 /// A BIP32 error
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[non_exhaustive]
-pub enum ParseError {
+pub enum Error {
+    /// A pk->pk derivation was attempted on a hardened key
+    CannotDeriveFromHardenedKey,
     /// A secp256k1 error occurred
     Secp256k1(secp256k1::Error),
+    /// A child number was provided that was out of range
+    InvalidChildNumber(u32),
+    /// Invalid childnumber format.
+    InvalidChildNumberFormat,
+    /// Invalid derivation path format.
+    InvalidDerivationPathFormat,
     /// Unknown version magic bytes
     UnknownVersion([u8; 4]),
     /// Encoded extended key data has wrong length
     WrongExtendedKeyLength(usize),
     /// Base58 encoding error
     Base58(base58::Error),
+    /// Hexadecimal decoding error
+    Hex(hex::HexToArrayError),
+    /// `PublicKey` hex should be 66 or 130 digits long.
+    InvalidPublicKeyHexLength(usize),
     /// Base58 decoded data was an invalid length.
     InvalidBase58PayloadLength(InvalidBase58PayloadLengthError),
     /// Invalid private key prefix (byte 45 must be 0)
@@ -522,20 +527,29 @@ pub enum ParseError {
     NonZeroChildNumberForMasterKey,
 }
 
-impl From<Infallible> for ParseError {
+impl From<Infallible> for Error {
     fn from(never: Infallible) -> Self { match never {} }
 }
 
-impl fmt::Display for ParseError {
+impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use ParseError::*;
+        use Error::*;
 
         match *self {
+            CannotDeriveFromHardenedKey =>
+                f.write_str("cannot derive hardened key from public key"),
             Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
+            InvalidChildNumber(ref n) =>
+                write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
+            InvalidChildNumberFormat => f.write_str("invalid child number format"),
+            InvalidDerivationPathFormat => f.write_str("invalid derivation path format"),
             UnknownVersion(ref bytes) => write!(f, "unknown version magic bytes: {:?}", bytes),
             WrongExtendedKeyLength(ref len) =>
                 write!(f, "encoded extended key data has wrong length {}", len),
             Base58(ref e) => write_err!(f, "base58 encoding error"; e),
+            Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e),
+            InvalidPublicKeyHexLength(got) =>
+                write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got),
             InvalidBase58PayloadLength(ref e) => write_err!(f, "base58 payload"; e),
             InvalidPrivateKeyPrefix =>
                 f.write_str("invalid private key prefix, byte 45 must be 0 as required by BIP-32"),
@@ -547,15 +561,22 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[cfg(feature = "std")]
-impl std::error::Error for ParseError {
+impl std::error::Error for Error {
     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        use ParseError::*;
+        use Error::*;
 
         match *self {
             Secp256k1(ref e) => Some(e),
             Base58(ref e) => Some(e),
+            Hex(ref e) => Some(e),
             InvalidBase58PayloadLength(ref e) => Some(e),
-            UnknownVersion(_) | WrongExtendedKeyLength(_) => None,
+            CannotDeriveFromHardenedKey
+            | InvalidChildNumber(_)
+            | InvalidChildNumberFormat
+            | InvalidDerivationPathFormat
+            | UnknownVersion(_)
+            | WrongExtendedKeyLength(_)
+            | InvalidPublicKeyHexLength(_) => None,
             InvalidPrivateKeyPrefix => None,
             NonZeroParentFingerprintForMasterKey => None,
             NonZeroChildNumberForMasterKey => None,
@@ -563,121 +584,35 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
     }
 }
 
-impl From<secp256k1::Error> for ParseError {
-    fn from(e: secp256k1::Error) -> ParseError { ParseError::Secp256k1(e) }
-}
-
-impl From<base58::Error> for ParseError {
-    fn from(err: base58::Error) -> Self { ParseError::Base58(err) }
-}
-
-impl From<InvalidBase58PayloadLengthError> for ParseError {
-    fn from(e: InvalidBase58PayloadLengthError) -> ParseError {
-        Self::InvalidBase58PayloadLength(e)
-    }
-}
-
-/// A BIP32 error
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum DerivationError {
-    /// Attempted to derive a hardened child from an xpub.
-    ///
-    /// You can only derive hardened children from xprivs.
-    CannotDeriveHardenedChild,
-    /// Attempted to derive a child of depth 256 or higher.
-    ///
-    /// There is no way to encode such xkeys.
-    MaximumDepthExceeded,
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for DerivationError {}
-
-impl fmt::Display for DerivationError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Self::CannotDeriveHardenedChild =>
-                f.write_str("cannot derive hardened child of public key"),
-            Self::MaximumDepthExceeded => f.write_str("cannot derive child of depth 256 or higher"),
-        }
-    }
-}
-
-/// Out-of-range index when constructing a child number.
-///
-/// *Indices* are always in the range [0, 2^31 - 1]. Normal child numbers have the
-/// same range, while hardened child numbers lie in the range [2^31, 2^32 - 1].
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
-pub struct IndexOutOfRangeError {
-    /// The index that was out of range for a child number.
-    pub index: u32,
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for IndexOutOfRangeError {}
-
-impl From<Infallible> for IndexOutOfRangeError {
-    fn from(never: Infallible) -> Self { match never {} }
-}
-
-impl fmt::Display for IndexOutOfRangeError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "index {} out of range [0, 2^31 - 1] (do you have an hardened child number, rather than an index?)", self.index)
-    }
-}
-
-/// Error parsing a child number.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ParseChildNumberError {
-    /// Parsed the child number as an integer, but the integer was out of range.
-    IndexOutOfRange(IndexOutOfRangeError),
-    /// Failed to parse the child number as an integer.
-    ParseInt(core::num::ParseIntError),
+impl From<secp256k1::Error> for Error {
+    fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
 }
 
-impl From<Infallible> for ParseChildNumberError {
-    fn from(never: Infallible) -> Self { match never {} }
+impl From<base58::Error> for Error {
+    fn from(err: base58::Error) -> Self { Error::Base58(err) }
 }
 
-#[cfg(feature = "std")]
-impl std::error::Error for ParseChildNumberError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match *self {
-            Self::IndexOutOfRange(ref e) => Some(e),
-            Self::ParseInt(ref e) => Some(e),
-        }
-    }
-}
-
-impl fmt::Display for ParseChildNumberError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Self::IndexOutOfRange(ref e) => e.fmt(f),
-            Self::ParseInt(ref e) => e.fmt(f),
-        }
-    }
+impl From<InvalidBase58PayloadLengthError> for Error {
+    fn from(e: InvalidBase58PayloadLengthError) -> Error { Self::InvalidBase58PayloadLength(e) }
 }
 
 impl Xpriv {
     /// Constructs a new master key from a seed value
-    pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Xpriv {
+    pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Result<Xpriv, Error> {
         let mut engine = HmacEngine::<sha512::HashEngine>::new(b"Bitcoin seed");
         engine.input(seed);
         let hmac = engine.finalize();
 
-        Xpriv {
+        Ok(Xpriv {
             network: network.into(),
             depth: 0,
             parent_fingerprint: Default::default(),
             child_number: ChildNumber::ZERO_NORMAL,
             private_key: secp256k1::SecretKey::from_byte_array(
                 hmac.as_byte_array().split_array::<32, 32>().0,
-            )
-            .expect("cryptographically unreachable"),
+            )?,
             chain_code: ChainCode::from_hmac(hmac),
-        }
+        })
     }
 
     /// Constructs a new ECDSA compressed private key matching internal secret key representation.
@@ -709,7 +644,7 @@ pub fn derive_priv<C: secp256k1::Signing, P: AsRef<[ChildNumber]>>(
         &self,
         secp: &Secp256k1<C>,
         path: &P,
-    ) -> Result<Xpriv, DerivationError> {
+    ) -> Xpriv {
         self.derive_xpriv(secp, path)
     }
 
@@ -720,20 +655,16 @@ pub fn derive_xpriv<C: secp256k1::Signing, P: AsRef<[ChildNumber]>>(
         &self,
         secp: &Secp256k1<C>,
         path: &P,
-    ) -> Result<Xpriv, DerivationError> {
+    ) -> Xpriv {
         let mut sk: Xpriv = *self;
         for cnum in path.as_ref() {
-            sk = sk.ckd_priv(secp, *cnum)?;
+            sk = sk.ckd_priv(secp, *cnum)
         }
-        Ok(sk)
+        sk
     }
 
     /// Private->Private child key derivation
-    fn ckd_priv<C: secp256k1::Signing>(
-        &self,
-        secp: &Secp256k1<C>,
-        i: ChildNumber,
-    ) -> Result<Xpriv, DerivationError> {
+    fn ckd_priv<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>, i: ChildNumber) -> Xpriv {
         let mut engine = HmacEngine::<sha512::HashEngine>::new(&self.chain_code[..]);
         match i {
             ChildNumber::Normal { .. } => {
@@ -757,30 +688,30 @@ fn ckd_priv<C: secp256k1::Signing>(
         let tweaked =
             sk.add_tweak(&self.private_key.into()).expect("statistically impossible to hit");
 
-        Ok(Xpriv {
+        Xpriv {
             network: self.network,
-            depth: self.depth.checked_add(1).ok_or(DerivationError::MaximumDepthExceeded)?,
+            depth: self.depth + 1,
             parent_fingerprint: self.fingerprint(secp),
             child_number: i,
             private_key: tweaked,
             chain_code: ChainCode::from_hmac(hmac),
-        })
+        }
     }
 
     /// Decoding extended private key from binary data according to BIP 32
-    pub fn decode(data: &[u8]) -> Result<Xpriv, ParseError> {
+    pub fn decode(data: &[u8]) -> Result<Xpriv, Error> {
         let Common { network, depth, parent_fingerprint, child_number, chain_code, key } =
             Common::decode(data)?;
 
         let network = match network {
             VERSION_BYTES_MAINNET_PRIVATE => NetworkKind::Main,
             VERSION_BYTES_TESTNETS_PRIVATE => NetworkKind::Test,
-            unknown => return Err(ParseError::UnknownVersion(unknown)),
+            unknown => return Err(Error::UnknownVersion(unknown)),
         };
 
         let (&zero, private_key) = key.split_first();
         if zero != 0 {
-            return Err(ParseError::InvalidPrivateKeyPrefix);
+            return Err(Error::InvalidPrivateKeyPrefix);
         }
 
         Ok(Xpriv {
@@ -863,7 +794,7 @@ pub fn derive_pub<C: secp256k1::Verification, P: AsRef<[ChildNumber]>>(
         &self,
         secp: &Secp256k1<C>,
         path: &P,
-    ) -> Result<Xpub, DerivationError> {
+    ) -> Result<Xpub, Error> {
         self.derive_xpub(secp, path)
     }
 
@@ -874,7 +805,7 @@ pub fn derive_xpub<C: secp256k1::Verification, P: AsRef<[ChildNumber]>>(
         &self,
         secp: &Secp256k1<C>,
         path: &P,
-    ) -> Result<Xpub, DerivationError> {
+    ) -> Result<Xpub, Error> {
         let mut pk: Xpub = *self;
         for cnum in path.as_ref() {
             pk = pk.ckd_pub(secp, *cnum)?
@@ -886,9 +817,9 @@ pub fn derive_xpub<C: secp256k1::Verification, P: AsRef<[ChildNumber]>>(
     pub fn ckd_pub_tweak(
         &self,
         i: ChildNumber,
-    ) -> Result<(secp256k1::SecretKey, ChainCode), DerivationError> {
+    ) -> Result<(secp256k1::SecretKey, ChainCode), Error> {
         match i {
-            ChildNumber::Hardened { .. } => Err(DerivationError::CannotDeriveHardenedChild),
+            ChildNumber::Hardened { .. } => Err(Error::CannotDeriveFromHardenedKey),
             ChildNumber::Normal { index: n } => {
                 let mut engine = HmacEngine::<sha512::HashEngine>::new(&self.chain_code[..]);
                 engine.input(&self.public_key.serialize()[..]);
@@ -897,8 +828,7 @@ pub fn ckd_pub_tweak(
                 let hmac = engine.finalize();
                 let private_key = secp256k1::SecretKey::from_byte_array(
                     hmac.as_byte_array().split_array::<32, 32>().0,
-                )
-                .expect("cryptographically unreachable");
+                )?;
                 let chain_code = ChainCode::from_hmac(hmac);
                 Ok((private_key, chain_code))
             }
@@ -910,14 +840,13 @@ pub fn ckd_pub<C: secp256k1::Verification>(
         &self,
         secp: &Secp256k1<C>,
         i: ChildNumber,
-    ) -> Result<Xpub, DerivationError> {
+    ) -> Result<Xpub, Error> {
         let (sk, chain_code) = self.ckd_pub_tweak(i)?;
-        let tweaked =
-            self.public_key.add_exp_tweak(secp, &sk.into()).expect("cryptographically unreachable");
+        let tweaked = self.public_key.add_exp_tweak(secp, &sk.into())?;
 
         Ok(Xpub {
             network: self.network,
-            depth: self.depth.checked_add(1).ok_or(DerivationError::MaximumDepthExceeded)?,
+            depth: self.depth + 1,
             parent_fingerprint: self.fingerprint(),
             child_number: i,
             public_key: tweaked,
@@ -926,14 +855,14 @@ pub fn ckd_pub<C: secp256k1::Verification>(
     }
 
     /// Decoding extended public key from binary data according to BIP 32
-    pub fn decode(data: &[u8]) -> Result<Xpub, ParseError> {
+    pub fn decode(data: &[u8]) -> Result<Xpub, Error> {
         let Common { network, depth, parent_fingerprint, child_number, chain_code, key } =
             Common::decode(data)?;
 
         let network = match network {
             VERSION_BYTES_MAINNET_PUBLIC => NetworkKind::Main,
             VERSION_BYTES_TESTNETS_PUBLIC => NetworkKind::Test,
-            unknown => return Err(ParseError::UnknownVersion(unknown)),
+            unknown => return Err(Error::UnknownVersion(unknown)),
         };
 
         Ok(Xpub {
@@ -979,9 +908,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl FromStr for Xpriv {
-    type Err = ParseError;
+    type Err = Error;
 
-    fn from_str(inp: &str) -> Result<Xpriv, ParseError> {
+    fn from_str(inp: &str) -> Result<Xpriv, Error> {
         let data = base58::decode_check(inp)?;
 
         if data.len() != 78 {
@@ -999,9 +928,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl FromStr for Xpub {
-    type Err = ParseError;
+    type Err = Error;
 
-    fn from_str(inp: &str) -> Result<Xpub, ParseError> {
+    fn from_str(inp: &str) -> Result<Xpub, Error> {
         let data = base58::decode_check(inp)?;
 
         if data.len() != 78 {
@@ -1057,9 +986,9 @@ struct Common {
 }
 
 impl Common {
-    fn decode(data: &[u8]) -> Result<Self, ParseError> {
+    fn decode(data: &[u8]) -> Result<Self, Error> {
         let data: &[u8; 78] =
-            data.try_into().map_err(|_| ParseError::WrongExtendedKeyLength(data.len()))?;
+            data.try_into().map_err(|_| Error::WrongExtendedKeyLength(data.len()))?;
 
         let (&network, data) = data.split_array::<4, 74>();
         let (&depth, data) = data.split_first::<73>();
@@ -1069,11 +998,11 @@ fn decode(data: &[u8]) -> Result<Self, ParseError> {
 
         if depth == 0 {
             if parent_fingerprint != [0u8; 4] {
-                return Err(ParseError::NonZeroParentFingerprintForMasterKey);
+                return Err(Error::NonZeroParentFingerprintForMasterKey);
             }
 
             if child_number != [0u8; 4] {
-                return Err(ParseError::NonZeroChildNumberForMasterKey);
+                return Err(Error::NonZeroChildNumberForMasterKey);
             }
         }
 
@@ -1099,25 +1028,13 @@ mod tests {
 
     #[test]
     fn parse_derivation_path() {
-        assert!(matches!(
-            "n/0'/0".parse::<DerivationPath>(),
-            Err(ParseChildNumberError::ParseInt(..)),
-        ));
-        assert!(matches!(
-            "4/m/5".parse::<DerivationPath>(),
-            Err(ParseChildNumberError::ParseInt(..)),
-        ));
-        assert!(matches!(
-            "//3/0'".parse::<DerivationPath>(),
-            Err(ParseChildNumberError::ParseInt(..)),
-        ));
-        assert!(matches!(
-            "0h/0x".parse::<DerivationPath>(),
-            Err(ParseChildNumberError::ParseInt(..)),
-        ));
+        assert_eq!("n/0'/0".parse::<DerivationPath>(), Err(Error::InvalidChildNumberFormat));
+        assert_eq!("4/m/5".parse::<DerivationPath>(), Err(Error::InvalidChildNumberFormat));
+        assert_eq!("//3/0'".parse::<DerivationPath>(), Err(Error::InvalidChildNumberFormat));
+        assert_eq!("0h/0x".parse::<DerivationPath>(), Err(Error::InvalidChildNumberFormat));
         assert_eq!(
             "2147483648".parse::<DerivationPath>(),
-            Err(ParseChildNumberError::IndexOutOfRange(IndexOutOfRangeError { index: 2147483648 })),
+            Err(Error::InvalidChildNumber(2147483648))
         );
 
         assert_eq!(DerivationPath::master(), "".parse::<DerivationPath>().unwrap());
@@ -1191,26 +1108,23 @@ fn test_path<C: secp256k1::Signing + secp256k1::Verification>(
         expected_sk: &str,
         expected_pk: &str,
     ) {
-        let mut sk = Xpriv::new_master(network, seed);
+        let mut sk = Xpriv::new_master(network, seed).unwrap();
         let mut pk = Xpub::from_xpriv(secp, &sk);
 
         // Check derivation convenience method for Xpriv
-        assert_eq!(&sk.derive_xpriv(secp, &path).unwrap().to_string()[..], expected_sk);
+        assert_eq!(&sk.derive_xpriv(secp, &path).to_string()[..], expected_sk);
 
         // Check derivation convenience method for Xpub, should error
         // appropriately if any ChildNumber is hardened
         if path.0.iter().any(|cnum| cnum.is_hardened()) {
-            assert_eq!(
-                pk.derive_xpub(secp, &path),
-                Err(DerivationError::CannotDeriveHardenedChild)
-            );
+            assert_eq!(pk.derive_xpub(secp, &path), Err(Error::CannotDeriveFromHardenedKey));
         } else {
             assert_eq!(&pk.derive_xpub(secp, &path).unwrap().to_string()[..], expected_pk);
         }
 
         // Derive keys, checking hardened and non-hardened derivation one-by-one
         for &num in path.0.iter() {
-            sk = sk.ckd_priv(secp, num).unwrap();
+            sk = sk.ckd_priv(secp, num);
             match num {
                 Normal { .. } => {
                     let pk2 = pk.ckd_pub(secp, num).unwrap();
@@ -1218,10 +1132,7 @@ fn test_path<C: secp256k1::Signing + secp256k1::Verification>(
                     assert_eq!(pk, pk2);
                 }
                 Hardened { .. } => {
-                    assert_eq!(
-                        pk.ckd_pub(secp, num),
-                        Err(DerivationError::CannotDeriveHardenedChild)
-                    );
+                    assert_eq!(pk.ckd_pub(secp, num), Err(Error::CannotDeriveFromHardenedKey));
                     pk = Xpub::from_xpriv(secp, &sk);
                 }
             }
@@ -1247,9 +1158,9 @@ fn increment() {
 
         let max = (1 << 31) - 1;
         let cn = ChildNumber::from_normal_idx(max).unwrap();
-        assert_eq!(cn.increment(), Err(IndexOutOfRangeError { index: 1 << 31 }),);
+        assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1 << 31)));
         let cn = ChildNumber::from_hardened_idx(max).unwrap();
-        assert_eq!(cn.increment(), Err(IndexOutOfRangeError { index: 1 << 31 }),);
+        assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1 << 31)));
 
         let cn = ChildNumber::from_normal_idx(350).unwrap();
         let path = "42'".parse::<DerivationPath>().unwrap();
@@ -1379,7 +1290,7 @@ fn test_reject_xpriv_with_non_zero_byte_at_index_45() {
         assert!(result.is_err());
 
         match result {
-            Err(ParseError::InvalidPrivateKeyPrefix) => {}
+            Err(Error::InvalidPrivateKeyPrefix) => {}
             _ => panic!("Expected InvalidPrivateKeyPrefix error, got {:?}", result),
         }
     }
@@ -1390,7 +1301,7 @@ fn test_reject_xpriv_with_zero_depth_and_non_zero_index() {
         assert!(result.is_err());
 
         match result {
-            Err(ParseError::NonZeroChildNumberForMasterKey) => {}
+            Err(Error::NonZeroChildNumberForMasterKey) => {}
             _ => panic!("Expected NonZeroChildNumberForMasterKey error, got {:?}", result),
         }
     }
@@ -1401,7 +1312,7 @@ fn test_reject_xpriv_with_zero_depth_and_non_zero_parent_fingerprint() {
         assert!(result.is_err());
 
         match result {
-            Err(ParseError::NonZeroParentFingerprintForMasterKey) => {}
+            Err(Error::NonZeroParentFingerprintForMasterKey) => {}
             _ => panic!("Expected NonZeroParentFingerprintForMasterKey error, got {:?}", result),
         }
     }
diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs
index 5fd59aa3..b88f2a19 100644
--- a/bitcoin/src/blockdata/block.rs
+++ b/bitcoin/src/blockdata/block.rs
@@ -30,7 +30,7 @@
 #[doc(inline)]
 pub use primitives::block::{Block, Checked, Unchecked, Validation, Version, BlockHash, Header, WitnessCommitment};
 #[doc(inline)]
-pub use units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightIntervalError};
+pub use units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightError};
 
 impl_hashencode!(BlockHash);
 
diff --git a/bitcoin/src/blockdata/mod.rs b/bitcoin/src/blockdata/mod.rs
index 8255e3cc..ab3b6746 100644
--- a/bitcoin/src/blockdata/mod.rs
+++ b/bitcoin/src/blockdata/mod.rs
@@ -41,11 +41,7 @@ pub mod absolute {
 
         /// Re-export everything from the `primitives::locktime::absolute` module.
         #[rustfmt::skip]        // Keep public re-exports separate.
-        pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, Mtp};
-
-        #[deprecated(since = "TBD", note = "use `Mtp` instead")]
-        #[doc(hidden)]
-        pub type Time = Mtp;
+        pub use primitives::locktime::absolute::{ConversionError, Height, LockTime, ParseHeightError, ParseTimeError, Time};
 
         impl Encodable for LockTime {
             #[inline]
@@ -71,17 +67,9 @@ pub mod relative {
 
         /// Re-export everything from the `primitives::locktime::relative` module.
         pub use primitives::locktime::relative::{
-            DisabledLockTimeError, HeightInterval, IncompatibleHeightError, IncompatibleTimeError,
-            LockTime, MtpInterval, TimeOverflowError,
+            DisabledLockTimeError, Height, IncompatibleHeightError, IncompatibleTimeError,
+            LockTime, Time, TimeOverflowError,
         };
-
-        #[deprecated(since = "TBD", note = "use `Mtp` instead")]
-        #[doc(hidden)]
-        pub type Height = HeightInterval;
-
-        #[deprecated(since = "TBD", note = "use `Mtp` instead")]
-        #[doc(hidden)]
-        pub type Time = MtpInterval;
     }
 }
 
diff --git a/bitcoin/src/blockdata/script/witness_program.rs b/bitcoin/src/blockdata/script/witness_program.rs
index 79a22dc8..f2780f85 100644
--- a/bitcoin/src/blockdata/script/witness_program.rs
+++ b/bitcoin/src/blockdata/script/witness_program.rs
@@ -101,13 +101,13 @@ pub fn p2tr<C: Verification>(
         merkle_root: Option<TapNodeHash>,
     ) -> Self {
         let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
-        let pubkey = output_key.as_x_only_public_key().serialize();
+        let pubkey = output_key.to_inner().serialize();
         WitnessProgram::new_p2tr(pubkey)
     }
 
     /// Constructs a new [`WitnessProgram`] from a tweaked key for a P2TR output.
     pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Self {
-        let pubkey = output_key.as_x_only_public_key().serialize();
+        let pubkey = output_key.to_inner().serialize();
         WitnessProgram::new_p2tr(pubkey)
     }
 
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index ff2d7d19..25859724 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -20,7 +20,7 @@
 use super::Weight;
 use crate::consensus::{self, encode, Decodable, Encodable};
 use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
-use crate::locktime::absolute::{self, Height, Mtp};
+use crate::locktime::absolute::{self, Height, Time};
 use crate::prelude::{Borrow, Vec};
 use crate::script::{Script, ScriptBuf, ScriptExt as _, ScriptExtPriv as _};
 #[cfg(doc)]
@@ -295,7 +295,7 @@ pub trait TransactionExt: sealed::Sealed {
     /// By definition if the lock time is not enabled the transaction's absolute timelock is
     /// considered to be satisfied i.e., there are no timelock constraints restricting this
     /// transaction from being mined immediately.
-    fn is_absolute_timelock_satisfied(&self, height: Height, time: Mtp) -> bool;
+    fn is_absolute_timelock_satisfied(&self, height: Height, time: Time) -> bool;
 
     /// Returns `true` if this transactions nLockTime is enabled ([BIP-65]).
     ///
@@ -393,7 +393,7 @@ fn is_coinbase(&self) -> bool {
 
     fn is_explicitly_rbf(&self) -> bool { self.input.iter().any(|input| input.sequence.is_rbf()) }
 
-    fn is_absolute_timelock_satisfied(&self, height: Height, time: Mtp) -> bool {
+    fn is_absolute_timelock_satisfied(&self, height: Height, time: Time) -> bool {
         if !self.is_lock_time_enabled() {
             return true;
         }
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index be464bc3..45a23294 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -887,18 +887,9 @@ pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> TweakedPublicKey {
         TweakedPublicKey(key)
     }
 
-    #[doc(hidden)]
-    #[deprecated(since = "0.33.0", note = "use to_x_only_public_key() instead")]
+    /// Returns the underlying public key.
     pub fn to_inner(self) -> XOnlyPublicKey { self.0 }
 
-    /// Returns the underlying x-only public key.
-    #[inline]
-    pub fn to_x_only_public_key(self) -> XOnlyPublicKey { self.0 }
-
-    /// Returns a reference to the underlying x-only public key.
-    #[inline]
-    pub fn as_x_only_public_key(&self) -> &XOnlyPublicKey { &self.0 }
-
     /// Serializes the key as a byte-encoded pair of values. In compressed form
     /// the y-coordinate is represented by only a single bit, as x determines
     /// it up to one bit.
@@ -915,17 +906,9 @@ impl TweakedKeypair {
     #[inline]
     pub fn dangerous_assume_tweaked(pair: Keypair) -> TweakedKeypair { TweakedKeypair(pair) }
 
-    #[doc(hidden)]
-    #[deprecated(since = "0.33.0", note = "use to_keypair() instead")]
-    pub fn to_inner(self) -> Keypair { self.0 }
-
     /// Returns the underlying key pair.
     #[inline]
-    pub fn to_keypair(self) -> Keypair { self.0 }
-
-    /// Returns a reference to the underlying key pair.
-    #[inline]
-    pub fn as_keypair(&self) -> &Keypair { &self.0 }
+    pub fn to_inner(self) -> Keypair { self.0 }
 
     /// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeypair`].
     #[inline]
diff --git a/bitcoin/src/p2p/address.rs b/bitcoin/src/p2p/address.rs
index 5bc8a679..8b3a1626 100644
--- a/bitcoin/src/p2p/address.rs
+++ b/bitcoin/src/p2p/address.rs
@@ -128,8 +128,6 @@ pub enum AddrV2 {
     Ipv4(Ipv4Addr),
     /// IPV6
     Ipv6(Ipv6Addr),
-    /// TORV2
-    TorV2([u8; 10]),
     /// TORV3
     TorV3([u8; 32]),
     /// I2P
@@ -152,7 +150,6 @@ fn encode_addr<W: Write + ?Sized>(
         Ok(match *self {
             AddrV2::Ipv4(ref addr) => encode_addr(w, 1, &addr.octets())?,
             AddrV2::Ipv6(ref addr) => encode_addr(w, 2, &addr.octets())?,
-            AddrV2::TorV2(ref bytes) => encode_addr(w, 3, bytes)?,
             AddrV2::TorV3(ref bytes) => encode_addr(w, 4, bytes)?,
             AddrV2::I2p(ref bytes) => encode_addr(w, 5, bytes)?,
             AddrV2::Cjdns(ref addr) => encode_addr(w, 6, &addr.octets())?,
@@ -195,13 +192,7 @@ fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Erro
                     addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
                 ))
             }
-            3 => {
-                if len != 10 {
-                    return Err(consensus::parse_failed_error("invalid TorV2 address"));
-                }
-                let id = Decodable::consensus_decode(r)?;
-                AddrV2::TorV2(id)
-            }
+
             4 => {
                 if len != 32 {
                     return Err(consensus::parse_failed_error("invalid TorV3 address"));
@@ -399,9 +390,6 @@ fn serialize_addrv2() {
             AddrV2::Ipv6("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b".parse::<Ipv6Addr>().unwrap());
         assert_eq!(serialize(&ip), hex!("02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b"));
 
-        let ip = AddrV2::TorV2(FromHex::from_hex("f1f2f3f4f5f6f7f8f9fa").unwrap());
-        assert_eq!(serialize(&ip), hex!("030af1f2f3f4f5f6f7f8f9fa"));
-
         let ip = AddrV2::TorV3(
             FromHex::from_hex("53cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88")
                 .unwrap(),
@@ -460,13 +448,6 @@ fn deserialize_addrv2() {
         // Invalid IPv6, contains embedded TORv2.
         assert!(deserialize::<AddrV2>(&hex!("0210fd87d87eeb430102030405060708090a")).is_err());
 
-        // Valid TORv2.
-        let ip: AddrV2 = deserialize(&hex!("030af1f2f3f4f5f6f7f8f9fa")).unwrap();
-        assert_eq!(ip, AddrV2::TorV2(FromHex::from_hex("f1f2f3f4f5f6f7f8f9fa").unwrap()));
-
-        // Invalid TORv2, with bogus length.
-        assert!(deserialize::<AddrV2>(&hex!("030700")).is_err());
-
         // Valid TORv3.
         let ip: AddrV2 = deserialize(&hex!(
             "042079bcc625184b05194975c28b66b66b0469f7f6556fb1ac3189a79b40dda32f1f"
diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs
index b9d6a936..2fef0a8b 100644
--- a/bitcoin/src/psbt/mod.rs
+++ b/bitcoin/src/psbt/mod.rs
@@ -448,7 +448,7 @@ fn bip32_sign_schnorr<C, K, T>(
                     let (msg, sighash_type) = self.sighash_taproot(input_index, cache, None)?;
                     let key_pair = Keypair::from_secret_key(secp, &sk.inner)
                         .tap_tweak(secp, input.tap_merkle_root)
-                        .to_keypair();
+                        .to_inner();
 
                     #[cfg(feature = "rand-std")]
                     let signature = secp.sign_schnorr(msg.as_ref(), &key_pair);
@@ -775,14 +775,14 @@ fn get_key<C: Signing>(
             KeyRequest::XOnlyPubkey(_) => Err(GetKeyError::NotSupported),
             KeyRequest::Bip32((fingerprint, path)) => {
                 let key = if self.fingerprint(secp) == *fingerprint {
-                    let k = self.derive_xpriv(secp, &path).map_err(GetKeyError::Bip32)?;
+                    let k = self.derive_xpriv(secp, &path);
                     Some(k.to_private_key())
                 } else if self.parent_fingerprint == *fingerprint
                     && !path.is_empty()
                     && path[0] == self.child_number
                 {
                     let path = DerivationPath::from_iter(path.into_iter().skip(1).copied());
-                    let k = self.derive_xpriv(secp, &path).map_err(GetKeyError::Bip32)?;
+                    let k = self.derive_xpriv(secp, &path);
                     Some(k.to_private_key())
                 } else {
                     None
@@ -915,8 +915,8 @@ fn get_key<C: Signing>(
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[non_exhaustive]
 pub enum GetKeyError {
-    /// A bip32 derivation error.
-    Bip32(bip32::DerivationError),
+    /// A bip32 error.
+    Bip32(bip32::Error),
     /// The GetKey operation is not supported for this key request.
     NotSupported,
 }
@@ -930,7 +930,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use GetKeyError::*;
 
         match *self {
-            Bip32(ref e) => write_err!(f, "bip32 derivation"; e),
+            Bip32(ref e) => write_err!(f, "a bip23 error"; e),
             NotSupported =>
                 f.write_str("the GetKey operation is not supported for this key request"),
         }
@@ -949,6 +949,10 @@ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
     }
 }
 
+impl From<bip32::Error> for GetKeyError {
+    fn from(e: bip32::Error) -> Self { GetKeyError::Bip32(e) }
+}
+
 /// The various output types supported by the Bitcoin network.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[non_exhaustive]
@@ -1436,7 +1440,7 @@ fn serialize_then_deserialize_output() {
 
         let mut hd_keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = Default::default();
 
-        let mut sk: Xpriv = Xpriv::new_master(NetworkKind::Main, &seed);
+        let mut sk: Xpriv = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
 
         let fprint = sk.fingerprint(secp);
 
@@ -1451,7 +1455,7 @@ fn serialize_then_deserialize_output() {
             ChildNumber::from_normal_idx(31337).unwrap(),
         ];
 
-        sk = sk.derive_xpriv(secp, &dpath).unwrap();
+        sk = sk.derive_xpriv(secp, &dpath);
 
         let pk = Xpub::from_xpriv(secp, &sk);
 
diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs
index 2a8c59c2..d1f40a26 100644
--- a/bitcoin/src/taproot/mod.rs
+++ b/bitcoin/src/taproot/mod.rs
@@ -1784,11 +1784,7 @@ fn _verify_tap_commitments(
         let script = ScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
         let control_block = ControlBlock::from_hex(control_block_hex).unwrap();
         assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
-        assert!(control_block.verify_taproot_commitment(
-            secp,
-            out_pk.to_x_only_public_key(),
-            &script
-        ));
+        assert!(control_block.verify_taproot_commitment(secp, out_pk.to_inner(), &script));
     }
 
     #[test]
@@ -1897,7 +1893,7 @@ fn build_huffman_tree() {
             let ctrl_block = tree_info.control_block(&ver_script).unwrap();
             assert!(ctrl_block.verify_taproot_commitment(
                 &secp,
-                output_key.to_x_only_public_key(),
+                output_key.to_inner(),
                 &ver_script.0
             ))
         }
@@ -1971,7 +1967,7 @@ fn taptree_builder() {
             let ctrl_block = tree_info.control_block(&ver_script).unwrap();
             assert!(ctrl_block.verify_taproot_commitment(
                 &secp,
-                output_key.to_x_only_public_key(),
+                output_key.to_inner(),
                 &ver_script.0
             ))
         }
@@ -2103,7 +2099,7 @@ fn process_script_trees(
             let addr = Address::p2tr(secp, internal_key, merkle_root, KnownHrp::Mainnet);
             let spk = addr.script_pubkey();
 
-            assert_eq!(expected_output_key, output_key.to_x_only_public_key());
+            assert_eq!(expected_output_key, output_key.to_inner());
             assert_eq!(expected_tweak, tweak);
             assert_eq!(expected_addr, addr);
             assert_eq!(expected_spk, spk);
diff --git a/githooks/post-merge b/githooks/post-merge
index 2d78934d..0ca51829 100755
--- a/githooks/post-merge
+++ b/githooks/post-merge
@@ -22,7 +22,7 @@ do
 			>&2 cat <<- EOF
 			==================================================
 			Project githooks have changed. Please inspect the
-			changes and re-run \`just githooks-install\` if
+			changes and re-reun \`just githooks-install\` if
 			they are legitimate.
 
 			Remove $HOOKS_DIR/post-merge to skip this warning
diff --git a/primitives/src/locktime/absolute.rs b/primitives/src/locktime/absolute.rs
index fff858a1..d6434ed8 100644
--- a/primitives/src/locktime/absolute.rs
+++ b/primitives/src/locktime/absolute.rs
@@ -16,11 +16,7 @@
 
 #[rustfmt::skip]                // Keep public re-exports separate.
 #[doc(inline)]
-pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, Mtp, LOCK_TIME_THRESHOLD};
-
-#[deprecated(since = "TBD", note = "use `Mtp` instead")]
-#[doc(hidden)]
-pub type Time = Mtp;
+pub use units::locktime::absolute::{ConversionError, Height, ParseHeightError, ParseTimeError, Time, LOCK_TIME_THRESHOLD};
 
 /// An absolute lock time value, representing either a block height or a UNIX timestamp (seconds
 /// since epoch).
@@ -83,7 +79,7 @@ pub enum LockTime {
     /// assert!(n.is_block_time());
     /// assert_eq!(n.to_consensus_u32(), seconds);
     /// ```
-    Seconds(Mtp),
+    Seconds(Time),
 }
 
 impl LockTime {
@@ -145,9 +141,9 @@ pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
     #[allow(clippy::missing_panics_doc)]
     pub fn from_consensus(n: u32) -> Self {
         if units::locktime::absolute::is_block_height(n) {
-            Self::Blocks(Height::from_u32(n).expect("n is valid"))
+            Self::Blocks(Height::from_consensus(n).expect("n is valid"))
         } else {
-            Self::Seconds(Mtp::from_u32(n).expect("n is valid"))
+            Self::Seconds(Time::from_consensus(n).expect("n is valid"))
         }
     }
 
@@ -170,23 +166,17 @@ pub fn from_consensus(n: u32) -> Self {
     /// ```
     #[inline]
     pub fn from_height(n: u32) -> Result<Self, ConversionError> {
-        let height = Height::from_u32(n)?;
+        let height = Height::from_consensus(n)?;
         Ok(LockTime::Blocks(height))
     }
 
-    #[inline]
-    #[deprecated(since = "TBD", note = "use `from_mtp` instead")]
-    #[doc(hidden)]
-    pub fn from_time(n: u32) -> Result<Self, ConversionError> { Self::from_mtp(n) }
-
-    /// Constructs a new `LockTime` from `n`, expecting `n` to be a median-time-past (MTP)
-    /// which is in range for a locktime.
+    /// Constructs a new `LockTime` from `n`, expecting `n` to be a valid block time.
     ///
     /// # Note
     ///
-    /// If the locktime is set to an MTP `T`, the transaction can be included in a block only if
-    /// the MTP of last recent 11 blocks is greater than `T`.
-    ///
+    /// If the locktime is set to a timestamp `T`,
+    /// the transaction can be included in a block only if the median time past (MTP) of the
+    /// last 11 blocks is greater than `T`.
     /// It is possible to broadcast the transaction once the MTP is greater than `T`.[see BIP-113]
     ///
     /// [BIP-113 Median time-past as endpoint for lock-time calculations](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki)
@@ -201,8 +191,8 @@ pub fn from_time(n: u32) -> Result<Self, ConversionError> { Self::from_mtp(n) }
     /// assert!(absolute::LockTime::from_time(741521).is_err());
     /// ```
     #[inline]
-    pub fn from_mtp(n: u32) -> Result<Self, ConversionError> {
-        let time = Mtp::from_u32(n)?;
+    pub fn from_time(n: u32) -> Result<Self, ConversionError> {
+        let time = Time::from_consensus(n)?;
         Ok(LockTime::Seconds(time))
     }
 
@@ -239,7 +229,7 @@ pub const fn is_block_time(self) -> bool { !self.is_block_height() }
     /// # use bitcoin_primitives::absolute;
     /// // Can be implemented if block chain data is available.
     /// fn get_height() -> absolute::Height { todo!("return the current block height") }
-    /// fn get_time() -> absolute::Mtp { todo!("return the current block time") }
+    /// fn get_time() -> absolute::Time { todo!("return the current block time") }
     ///
     /// let n = absolute::LockTime::from_consensus(741521); // `n OP_CHEKCLOCKTIMEVERIFY`.
     /// if n.is_satisfied_by(get_height(), get_time()) {
@@ -247,7 +237,7 @@ pub const fn is_block_time(self) -> bool { !self.is_block_height() }
     /// }
     /// ````
     #[inline]
-    pub fn is_satisfied_by(self, height: Height, time: Mtp) -> bool {
+    pub fn is_satisfied_by(self, height: Height, time: Time) -> bool {
         use LockTime as L;
 
         match self {
@@ -263,15 +253,9 @@ pub fn is_satisfied_by(self, height: Height, time: Mtp) -> bool {
     /// two lock times (same unit) then the larger lock time being satisfied implies (in a
     /// mathematical sense) the smaller one being satisfied.
     ///
-    /// This function serves multiple purposes:
-    ///
-    /// * When evaluating `OP_CHECKLOCKTIMEVERIFY` the argument must be less than or equal to the
-    ///   transactions nLockTime. If using this function to validate a script `self` is the argument
-    ///   to `CLTV` and `other` is the transaction nLockTime.
-    ///
-    /// * If you wish to check a lock time against various other locks e.g., filtering out locks
-    ///   which cannot be satisfied. Can also be used to remove the smaller value of two
-    ///   `OP_CHECKLOCKTIMEVERIFY` operations within one branch of the script.
+    /// This function is useful if you wish to check a lock time against various other locks e.g.,
+    /// filtering out locks which cannot be satisfied. Can also be used to remove the smaller value
+    /// of two `OP_CHECKLOCKTIMEVERIFY` operations within one branch of the script.
     ///
     /// # Examples
     ///
@@ -320,8 +304,8 @@ pub fn is_implied_by(self, other: LockTime) -> bool {
     #[inline]
     pub fn to_consensus_u32(self) -> u32 {
         match self {
-            LockTime::Blocks(ref h) => h.to_u32(),
-            LockTime::Seconds(ref t) => t.to_u32(),
+            LockTime::Blocks(ref h) => h.to_consensus_u32(),
+            LockTime::Seconds(ref t) => t.to_consensus_u32(),
         }
     }
 }
@@ -333,9 +317,9 @@ impl From<Height> for LockTime {
     fn from(h: Height) -> Self { LockTime::Blocks(h) }
 }
 
-impl From<Mtp> for LockTime {
+impl From<Time> for LockTime {
     #[inline]
-    fn from(t: Mtp) -> Self { LockTime::Seconds(t) }
+    fn from(t: Time) -> Self { LockTime::Seconds(t) }
 }
 
 impl fmt::Debug for LockTime {
@@ -422,7 +406,7 @@ mod tests {
     #[test]
     fn display_and_alternate() {
         let lock_by_height = LockTime::from_height(741_521).unwrap();
-        let lock_by_time = LockTime::from_mtp(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC.
+        let lock_by_time = LockTime::from_time(1_653_195_600).unwrap(); // May 22nd 2022, 5am UTC.
 
         assert_eq!(format!("{}", lock_by_height), "741521");
         assert_eq!(format!("{:#}", lock_by_height), "block-height 741521");
@@ -478,9 +462,9 @@ fn invalid_locktime_type() {
         assert!(LockTime::from_height(500_000_000).is_err()); // The threshold.
         assert!(LockTime::from_height(500_000_001).is_err()); // Above the threshold.
 
-        assert!(LockTime::from_mtp(499_999_999).is_err()); // Below the threshold.
-        assert!(LockTime::from_mtp(500_000_000).is_ok()); // The threshold.
-        assert!(LockTime::from_mtp(500_000_001).is_ok()); // Above the threshold.
+        assert!(LockTime::from_time(499_999_999).is_err()); // Below the threshold.
+        assert!(LockTime::from_time(500_000_000).is_ok()); // The threshold.
+        assert!(LockTime::from_time(500_000_001).is_ok()); // Above the threshold.
     }
 
     #[test]
@@ -505,14 +489,14 @@ fn parses_correctly_to_height_or_time() {
 
     #[test]
     fn satisfied_by_height() {
-        let height_below = Height::from_u32(700_000).unwrap();
-        let height = Height::from_u32(750_000).unwrap();
-        let height_above = Height::from_u32(800_000).unwrap();
+        let height_below = Height::from_consensus(700_000).unwrap();
+        let height = Height::from_consensus(750_000).unwrap();
+        let height_above = Height::from_consensus(800_000).unwrap();
 
         let lock_by_height = LockTime::from(height);
 
         let t: u32 = 1_653_195_600; // May 22nd, 5am UTC.
-        let time = Mtp::from_u32(t).unwrap();
+        let time = Time::from_consensus(t).unwrap();
 
         assert!(!lock_by_height.is_satisfied_by(height_below, time));
         assert!(lock_by_height.is_satisfied_by(height, time));
@@ -521,13 +505,13 @@ fn satisfied_by_height() {
 
     #[test]
     fn satisfied_by_time() {
-        let time_before = Mtp::from_u32(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC.
-        let time = Mtp::from_u32(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC.
-        let time_after = Mtp::from_u32(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
+        let time_before = Time::from_consensus(1_653_109_200).unwrap(); // "May 21th 2022, 5am UTC.
+        let time = Time::from_consensus(1_653_195_600).unwrap(); // "May 22nd 2022, 5am UTC.
+        let time_after = Time::from_consensus(1_653_282_000).unwrap(); // "May 23rd 2022, 5am UTC.
 
         let lock_by_time = LockTime::from(time);
 
-        let height = Height::from_u32(800_000).unwrap();
+        let height = Height::from_consensus(800_000).unwrap();
 
         assert!(!lock_by_time.is_satisfied_by(height, time_before));
         assert!(lock_by_time.is_satisfied_by(height, time));
diff --git a/primitives/src/locktime/relative.rs b/primitives/src/locktime/relative.rs
index 053e883c..3493e37f 100644
--- a/primitives/src/locktime/relative.rs
+++ b/primitives/src/locktime/relative.rs
@@ -13,17 +13,9 @@
 
 #[rustfmt::skip]                // Keep public re-exports separate.
 #[doc(inline)]
-pub use units::locktime::relative::{HeightInterval, MtpInterval, TimeOverflowError};
+pub use units::locktime::relative::{Height, Time, TimeOverflowError};
 use units::mtp_height::MtpAndHeight;
 
-#[deprecated(since = "TBD", note = "use `Mtp` instead")]
-#[doc(hidden)]
-pub type Height = HeightInterval;
-
-#[deprecated(since = "TBD", note = "use `Mtp` instead")]
-#[doc(hidden)]
-pub type Time = MtpInterval;
-
 /// A relative lock time value, representing either a block height or time (512 second intervals).
 ///
 /// Used for sequence numbers (`nSequence` in Bitcoin Core and [`TxIn::sequence`]
@@ -69,7 +61,7 @@
 ///
 /// let chain_tip = MtpAndHeight::new(current_height, timestamps);
 /// let utxo_mined_at = MtpAndHeight::new(utxo_height, utxo_timestamps);
-/// let locktime = relative::LockTime::Time(relative::MtpInterval::from_512_second_intervals(10));
+/// let locktime = relative::LockTime::Time(relative::Time::from_512_second_intervals(10));
 ///
 /// // Check if locktime is satisfied
 /// assert!(locktime.is_satisfied_by(chain_tip, utxo_mined_at));
@@ -78,15 +70,15 @@
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 pub enum LockTime {
     /// A block height lock time value.
-    Blocks(HeightInterval),
+    Blocks(Height),
     /// A 512 second time interval value.
-    Time(MtpInterval),
+    Time(Time),
 }
 
 impl LockTime {
     /// A relative locktime of 0 is always valid, and is assumed valid for inputs that
     /// are not yet confirmed.
-    pub const ZERO: LockTime = LockTime::Blocks(HeightInterval::ZERO);
+    pub const ZERO: LockTime = LockTime::Blocks(Height::ZERO);
 
     /// The number of bytes that the locktime contributes to the size of a transaction.
     pub const SIZE: usize = 4; // Serialized length of a u32.
@@ -132,9 +124,8 @@ pub fn from_consensus(n: u32) -> Result<Self, DisabledLockTimeError> {
     #[inline]
     pub fn to_consensus_u32(self) -> u32 {
         match self {
-            LockTime::Blocks(ref h) => u32::from(h.to_height()),
-            LockTime::Time(ref t) =>
-                Sequence::LOCK_TYPE_MASK | u32::from(t.to_512_second_intervals()),
+            LockTime::Blocks(ref h) => h.to_consensus_u32(),
+            LockTime::Time(ref t) => t.to_consensus_u32(),
         }
     }
 
@@ -165,7 +156,7 @@ pub fn to_sequence(self) -> Sequence { Sequence::from_consensus(self.to_consensu
 
     /// Constructs a new `LockTime` from `n`, expecting `n` to be a 16-bit count of blocks.
     #[inline]
-    pub const fn from_height(n: u16) -> Self { LockTime::Blocks(HeightInterval::from_height(n)) }
+    pub const fn from_height(n: u16) -> Self { LockTime::Blocks(Height::from_height(n)) }
 
     /// Constructs a new `LockTime` from `n`, expecting `n` to be a count of 512-second intervals.
     ///
@@ -173,7 +164,7 @@ pub const fn from_height(n: u16) -> Self { LockTime::Blocks(HeightInterval::from
     /// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`].
     #[inline]
     pub const fn from_512_second_intervals(intervals: u16) -> Self {
-        LockTime::Time(MtpInterval::from_512_second_intervals(intervals))
+        LockTime::Time(Time::from_512_second_intervals(intervals))
     }
 
     /// Construct a new [`LockTime`] from seconds, converting the seconds into 512 second interval
@@ -184,7 +175,7 @@ pub const fn from_512_second_intervals(intervals: u16) -> Self {
     /// Will return an error if the input cannot be encoded in 16 bits.
     #[inline]
     pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
-        match MtpInterval::from_seconds_floor(seconds) {
+        match Time::from_seconds_floor(seconds) {
             Ok(time) => Ok(LockTime::Time(time)),
             Err(e) => Err(e),
         }
@@ -198,7 +189,7 @@ pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError>
     /// Will return an error if the input cannot be encoded in 16 bits.
     #[inline]
     pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
-        match MtpInterval::from_seconds_ceil(seconds) {
+        match Time::from_seconds_ceil(seconds) {
             Ok(time) => Ok(LockTime::Time(time)),
             Err(e) => Err(e),
         }
@@ -225,7 +216,7 @@ pub const fn is_block_time(self) -> bool { !self.is_block_height() }
     /// # Examples
     ///
     /// ```rust
-    /// # use bitcoin_primitives::locktime::relative::HeightInterval;
+    /// # use bitcoin_primitives::locktime::relative::Height;
     /// # use bitcoin_primitives::relative::Time;
     /// # use units::mtp_height::MtpAndHeight;
     /// # use bitcoin_primitives::BlockHeight;
@@ -294,8 +285,8 @@ pub fn is_implied_by(self, other: LockTime) -> bool {
         use LockTime as L;
 
         match (self, other) {
-            (L::Blocks(this), L::Blocks(other)) => this <= other,
-            (L::Time(this), L::Time(other)) => this <= other,
+            (L::Blocks(this), L::Blocks(other)) => this.value() <= other.value(),
+            (L::Time(this), L::Time(other)) => this.value() <= other.value(),
             _ => false, // Not the same units.
         }
     }
@@ -329,7 +320,7 @@ pub fn is_implied_by_sequence(self, other: Sequence) -> bool {
         }
     }
 
-    /// Returns true if this [`relative::LockTime`] is satisfied by [`HeightInterval`].
+    /// Returns true if this [`relative::LockTime`] is satisfied by [`Height`].
     ///
     /// # Errors
     ///
@@ -343,17 +334,14 @@ pub fn is_implied_by_sequence(self, other: Sequence) -> bool {
     ///
     /// let required_height: u16 = 100;
     /// let lock = Sequence::from_height(required_height).to_relative_lock_time().expect("valid height");
-    /// assert!(lock.is_satisfied_by_height(relative::HeightInterval::from(required_height + 1)).expect("a height"));
+    /// assert!(lock.is_satisfied_by_height(relative::Height::from(required_height + 1)).expect("a height"));
     /// ```
     #[inline]
-    pub fn is_satisfied_by_height(
-        self,
-        height: HeightInterval,
-    ) -> Result<bool, IncompatibleHeightError> {
+    pub fn is_satisfied_by_height(self, height: Height) -> Result<bool, IncompatibleHeightError> {
         use LockTime as L;
 
         match self {
-            L::Blocks(required_height) => Ok(required_height <= height),
+            L::Blocks(ref required_height) => Ok(required_height.value() <= height.value()),
             L::Time(time) => Err(IncompatibleHeightError { height, time }),
         }
     }
@@ -375,24 +363,24 @@ pub fn is_satisfied_by_height(
     /// assert!(lock.is_satisfied_by_time(relative::Time::from_512_second_intervals(intervals + 10)).expect("a time"));
     /// ```
     #[inline]
-    pub fn is_satisfied_by_time(self, time: MtpInterval) -> Result<bool, IncompatibleTimeError> {
+    pub fn is_satisfied_by_time(self, time: Time) -> Result<bool, IncompatibleTimeError> {
         use LockTime as L;
 
         match self {
-            L::Time(ref t) => Ok(t.to_512_second_intervals() <= time.to_512_second_intervals()),
+            L::Time(ref t) => Ok(t.value() <= time.value()),
             L::Blocks(height) => Err(IncompatibleTimeError { time, height }),
         }
     }
 }
 
-impl From<HeightInterval> for LockTime {
+impl From<Height> for LockTime {
     #[inline]
-    fn from(h: HeightInterval) -> Self { LockTime::Blocks(h) }
+    fn from(h: Height) -> Self { LockTime::Blocks(h) }
 }
 
-impl From<MtpInterval> for LockTime {
+impl From<Time> for LockTime {
     #[inline]
-    fn from(t: MtpInterval) -> Self { LockTime::Time(t) }
+    fn from(t: Time) -> Self { LockTime::Time(t) }
 }
 
 impl fmt::Display for LockTime {
@@ -452,17 +440,17 @@ impl std::error::Error for DisabledLockTimeError {}
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct IncompatibleHeightError {
     /// Attempted to satisfy a lock-by-blocktime lock with this height.
-    height: HeightInterval,
+    height: Height,
     /// The inner time value of the lock-by-blocktime lock.
-    time: MtpInterval,
+    time: Time,
 }
 
 impl IncompatibleHeightError {
     /// Returns the height that was erroneously used to try and satisfy a lock-by-blocktime lock.
-    pub fn incompatible(&self) -> HeightInterval { self.height }
+    pub fn incompatible(&self) -> Height { self.height }
 
     /// Returns the time value of the lock-by-blocktime lock.
-    pub fn expected(&self) -> MtpInterval { self.time }
+    pub fn expected(&self) -> Time { self.time }
 }
 
 impl fmt::Display for IncompatibleHeightError {
@@ -483,17 +471,17 @@ impl std::error::Error for IncompatibleHeightError {}
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct IncompatibleTimeError {
     /// Attempted to satisfy a lock-by-blockheight lock with this time.
-    time: MtpInterval,
+    time: Time,
     /// The inner height value of the lock-by-blockheight lock.
-    height: HeightInterval,
+    height: Height,
 }
 
 impl IncompatibleTimeError {
     /// Returns the time that was erroneously used to try and satisfy a lock-by-blockheight lock.
-    pub fn incompatible(&self) -> MtpInterval { self.time }
+    pub fn incompatible(&self) -> Time { self.time }
 
     /// Returns the height value of the lock-by-blockheight lock.
-    pub fn expected(&self) -> HeightInterval { self.height }
+    pub fn expected(&self) -> Height { self.height }
 }
 
 impl fmt::Display for IncompatibleTimeError {
@@ -548,10 +536,10 @@ fn from_seconds_ceil_and_floor() {
 
     #[test]
     fn parses_correctly_to_height_or_time() {
-        let height1 = HeightInterval::from(10);
-        let height2 = HeightInterval::from(11);
-        let time1 = MtpInterval::from_512_second_intervals(70);
-        let time2 = MtpInterval::from_512_second_intervals(71);
+        let height1 = Height::from(10);
+        let height2 = Height::from(11);
+        let time1 = Time::from_512_second_intervals(70);
+        let time2 = Time::from_512_second_intervals(71);
 
         let lock_by_height1 = LockTime::from(height1);
         let lock_by_height2 = LockTime::from(height2);
@@ -573,34 +561,28 @@ fn parses_correctly_to_height_or_time() {
 
     #[test]
     fn height_correctly_implies() {
-        let height = HeightInterval::from(10);
+        let height = Height::from(10);
         let lock_by_height = LockTime::from(height);
 
-        assert!(!lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(9))));
-        assert!(lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(10))));
-        assert!(lock_by_height.is_implied_by(LockTime::from(HeightInterval::from(11))));
+        assert!(!lock_by_height.is_implied_by(LockTime::from(Height::from(9))));
+        assert!(lock_by_height.is_implied_by(LockTime::from(Height::from(10))));
+        assert!(lock_by_height.is_implied_by(LockTime::from(Height::from(11))));
     }
 
     #[test]
     fn time_correctly_implies() {
-        let time = MtpInterval::from_512_second_intervals(70);
+        let time = Time::from_512_second_intervals(70);
         let lock_by_time = LockTime::from(time);
 
-        assert!(
-            !lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(69)))
-        );
-        assert!(
-            lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(70)))
-        );
-        assert!(
-            lock_by_time.is_implied_by(LockTime::from(MtpInterval::from_512_second_intervals(71)))
-        );
+        assert!(!lock_by_time.is_implied_by(LockTime::from(Time::from_512_second_intervals(69))));
+        assert!(lock_by_time.is_implied_by(LockTime::from(Time::from_512_second_intervals(70))));
+        assert!(lock_by_time.is_implied_by(LockTime::from(Time::from_512_second_intervals(71))));
     }
 
     #[test]
     fn sequence_correctly_implies() {
-        let height = HeightInterval::from(10);
-        let time = MtpInterval::from_512_second_intervals(70);
+        let height = Height::from(10);
+        let time = Time::from_512_second_intervals(70);
 
         let lock_by_height = LockTime::from(height);
         let lock_by_time = LockTime::from(time);
@@ -621,8 +603,8 @@ fn sequence_correctly_implies() {
 
     #[test]
     fn incorrect_units_do_not_imply() {
-        let time = MtpInterval::from_512_second_intervals(70);
-        let height = HeightInterval::from(10);
+        let time = Time::from_512_second_intervals(70);
+        let height = Height::from(10);
 
         let lock_by_time = LockTime::from(time);
         assert!(!lock_by_time.is_implied_by(LockTime::from(height)));
@@ -661,8 +643,8 @@ fn disabled_locktime_error() {
 
     #[test]
     fn incompatible_height_error() {
-        let height = HeightInterval::from(10);
-        let time = MtpInterval::from_512_second_intervals(70);
+        let height = Height::from(10);
+        let time = Time::from_512_second_intervals(70);
         let lock_by_time = LockTime::from(time);
         let err = lock_by_time.is_satisfied_by_height(height).unwrap_err();
 
@@ -673,8 +655,8 @@ fn incompatible_height_error() {
 
     #[test]
     fn incompatible_time_error() {
-        let height = HeightInterval::from(10);
-        let time = MtpInterval::from_512_second_intervals(70);
+        let height = Height::from(10);
+        let time = Time::from_512_second_intervals(70);
         let lock_by_height = LockTime::from(height);
         let err = lock_by_height.is_satisfied_by_time(time).unwrap_err();
 
@@ -699,16 +681,16 @@ fn test_locktime_chain_state() {
         let chain_tip = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
         let utxo_mined_at = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
 
-        let lock1 = LockTime::Blocks(HeightInterval::from(10));
+        let lock1 = LockTime::Blocks(Height::from(10));
         assert!(lock1.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let lock2 = LockTime::Blocks(HeightInterval::from(21));
+        let lock2 = LockTime::Blocks(Height::from(21));
         assert!(!lock2.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let lock3 = LockTime::Time(MtpInterval::from_512_second_intervals(10));
+        let lock3 = LockTime::Time(Time::from_512_second_intervals(10));
         assert!(lock3.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let lock4 = LockTime::Time(MtpInterval::from_512_second_intervals(20000));
+        let lock4 = LockTime::Time(Time::from_512_second_intervals(20000));
         assert!(!lock4.is_satisfied_by(chain_tip, utxo_mined_at));
 
         assert!(LockTime::ZERO.is_satisfied_by(chain_tip, utxo_mined_at));
@@ -717,10 +699,10 @@ fn test_locktime_chain_state() {
         let lock6 = LockTime::from_seconds_floor(5000).unwrap();
         assert!(lock6.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let max_height_lock = LockTime::Blocks(HeightInterval::MAX);
+        let max_height_lock = LockTime::Blocks(Height::MAX);
         assert!(!max_height_lock.is_satisfied_by(chain_tip, utxo_mined_at));
 
-        let max_time_lock = LockTime::Time(MtpInterval::MAX);
+        let max_time_lock = LockTime::Time(Time::MAX);
         assert!(!max_time_lock.is_satisfied_by(chain_tip, utxo_mined_at));
 
         let max_chain_tip =
diff --git a/primitives/src/sequence.rs b/primitives/src/sequence.rs
index b659c98e..df291b7e 100644
--- a/primitives/src/sequence.rs
+++ b/primitives/src/sequence.rs
@@ -70,7 +70,7 @@ impl Sequence {
     /// BIP-68 relative lock time disable flag mask.
     const LOCK_TIME_DISABLE_FLAG_MASK: u32 = 0x8000_0000;
     /// BIP-68 relative lock time type flag mask.
-    pub(super) const LOCK_TYPE_MASK: u32 = 0x0040_0000;
+    const LOCK_TYPE_MASK: u32 = 0x0040_0000;
 
     /// Returns `true` if the sequence number enables absolute lock-time ([`Transaction::lock_time`]).
     #[inline]
@@ -187,7 +187,7 @@ pub fn to_consensus_u32(self) -> u32 { self.0 }
     /// Constructs a new [`relative::LockTime`] from this [`Sequence`] number.
     #[inline]
     pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
-        use crate::locktime::relative::{HeightInterval, LockTime, MtpInterval};
+        use crate::locktime::relative::{Height, LockTime, Time};
 
         if !self.is_relative_lock_time() {
             return None;
@@ -196,9 +196,9 @@ pub fn to_relative_lock_time(self) -> Option<relative::LockTime> {
         let lock_value = self.low_u16();
 
         if self.is_time_locked() {
-            Some(LockTime::from(MtpInterval::from_512_second_intervals(lock_value)))
+            Some(LockTime::from(Time::from_512_second_intervals(lock_value)))
         } else {
-            Some(LockTime::from(HeightInterval::from(lock_value)))
+            Some(LockTime::from(Height::from(lock_value)))
         }
     }
 
@@ -261,16 +261,10 @@ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
             1 => Ok(Sequence::ZERO),
             2 => Ok(Sequence::MIN_NO_RBF),
             3 => Ok(Sequence::ENABLE_LOCKTIME_AND_RBF),
-            4 => Ok(Sequence::from_consensus(u32::from(relative::HeightInterval::MIN.to_height()))),
-            5 => Ok(Sequence::from_consensus(u32::from(relative::HeightInterval::MAX.to_height()))),
-            6 => Ok(Sequence::from_consensus(
-                Sequence::LOCK_TYPE_MASK
-                    | u32::from(relative::MtpInterval::MIN.to_512_second_intervals()),
-            )),
-            7 => Ok(Sequence::from_consensus(
-                Sequence::LOCK_TYPE_MASK
-                    | u32::from(relative::MtpInterval::MAX.to_512_second_intervals()),
-            )),
+            4 => Ok(Sequence::from_consensus(relative::Height::MIN.to_consensus_u32())),
+            5 => Ok(Sequence::from_consensus(relative::Height::MAX.to_consensus_u32())),
+            6 => Ok(Sequence::from_consensus(relative::Time::MIN.to_consensus_u32())),
+            7 => Ok(Sequence::from_consensus(relative::Time::MAX.to_consensus_u32())),
             _ => Ok(Sequence(u.arbitrary()?)),
         }
     }
@@ -360,11 +354,4 @@ fn sequence_formatting() {
         let sequence_u32: u32 = sequence.into();
         assert_eq!(sequence_u32, 0x7FFF_FFFF);
     }
-
-    #[test]
-    fn sequence_display() {
-        let sequence = Sequence(0x7FFF_FFFF);
-        let want: u32 = 0x7FFF_FFFF;
-        assert_eq!(format!("{}", sequence), want.to_string());
-    }
 }
diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs
index 10176ef7..2727551d 100644
--- a/primitives/src/transaction.rs
+++ b/primitives/src/transaction.rs
@@ -748,19 +748,4 @@ fn canonical_vout() {
         assert!(parse_vout("01").is_err()); // Leading zero not allowed
         assert!(parse_vout("+1").is_err()); // Non digits not allowed
     }
-
-    #[test]
-    #[cfg(feature = "alloc")]
-    #[cfg(feature = "hex")]
-    fn outpoint_display_roundtrip() {
-        let outpoint_str = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20:1";
-        let outpoint: OutPoint = outpoint_str.parse().unwrap();
-        assert_eq!(format!("{}", outpoint), outpoint_str);
-    }
-
-    #[test]
-    fn version_display() {
-        let version = Version(123);
-        assert_eq!(format!("{}", version), "123");
-    }
 }
diff --git a/units/src/block.rs b/units/src/block.rs
index 000f0995..5d0dc90b 100644
--- a/units/src/block.rs
+++ b/units/src/block.rs
@@ -70,7 +70,7 @@ impl From<absolute::Height> for BlockHeight {
     /// An absolute locktime block height has a maximum value of [`absolute::LOCK_TIME_THRESHOLD`]
     /// (500,000,000) where as a [`BlockHeight`] is a thin wrapper around a `u32`, the two types are
     /// not interchangeable.
-    fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_u32()) }
+    fn from(h: absolute::Height) -> Self { Self::from_u32(h.to_consensus_u32()) }
 }
 
 impl TryFrom<BlockHeight> for absolute::Height {
@@ -82,7 +82,7 @@ impl TryFrom<BlockHeight> for absolute::Height {
     /// (500,000,000) where as a [`BlockHeight`] is a thin wrapper around a `u32`, the two types are
     /// not interchangeable.
     fn try_from(h: BlockHeight) -> Result<Self, Self::Error> {
-        absolute::Height::from_u32(h.to_u32())
+        absolute::Height::from_consensus(h.to_u32())
     }
 }
 
@@ -129,48 +129,47 @@ impl From<BlockInterval> for u32 {
     fn from(height: BlockInterval) -> Self { height.to_u32() }
 }
 
-impl From<relative::HeightInterval> for BlockInterval {
-    /// Converts a [`locktime::relative::HeightInterval`] to a [`BlockInterval`].
+impl From<relative::Height> for BlockInterval {
+    /// Converts a [`locktime::relative::Height`] to a [`BlockInterval`].
     ///
     /// A relative locktime block height has a maximum value of `u16::MAX` where as a
     /// [`BlockInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
-    fn from(h: relative::HeightInterval) -> Self { Self::from_u32(h.to_height().into()) }
+    fn from(h: relative::Height) -> Self { Self::from_u32(h.value().into()) }
 }
 
-impl TryFrom<BlockInterval> for relative::HeightInterval {
-    type Error = TooBigForRelativeBlockHeightIntervalError;
+impl TryFrom<BlockInterval> for relative::Height {
+    type Error = TooBigForRelativeBlockHeightError;
 
-    /// Converts a [`BlockInterval`] to a [`locktime::relative::HeightInterval`].
+    /// Converts a [`BlockInterval`] to a [`locktime::relative::Height`].
     ///
     /// A relative locktime block height has a maximum value of `u16::MAX` where as a
     /// [`BlockInterval`] is a thin wrapper around a `u32`, the two types are not interchangeable.
     fn try_from(h: BlockInterval) -> Result<Self, Self::Error> {
         let h = h.to_u32();
-
         if h > u32::from(u16::MAX) {
-            return Err(TooBigForRelativeBlockHeightIntervalError(h));
+            return Err(TooBigForRelativeBlockHeightError(h));
         }
-        Ok(relative::HeightInterval::from(h as u16)) // Cast ok, value checked above.
+        Ok(relative::Height::from(h as u16)) // Cast ok, value checked above.
     }
 }
 
 /// Error returned when the block interval is too big to be used as a relative lock time.
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct TooBigForRelativeBlockHeightIntervalError(u32);
+pub struct TooBigForRelativeBlockHeightError(u32);
 
-impl fmt::Display for TooBigForRelativeBlockHeightIntervalError {
+impl fmt::Display for TooBigForRelativeBlockHeightError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(
             f,
             "block interval is too big to be used as a relative lock time: {} (max: {})",
             self.0,
-            relative::HeightInterval::MAX
+            relative::Height::MAX
         )
     }
 }
 
 #[cfg(feature = "std")]
-impl std::error::Error for TooBigForRelativeBlockHeightIntervalError {}
+impl std::error::Error for TooBigForRelativeBlockHeightError {}
 
 crate::internal_macros::impl_op_for_references! {
     // height - height = interval
@@ -280,14 +279,14 @@ fn sanity_check() {
         let interval: u32 = BlockInterval(100).into();
         assert_eq!(interval, 100);
 
-        let interval_from_height: BlockInterval = relative::HeightInterval::from(10u16).into();
+        let interval_from_height: BlockInterval = relative::Height::from(10u16).into();
         assert_eq!(interval_from_height.to_u32(), 10u32);
 
         let invalid_height_greater =
-            relative::HeightInterval::try_from(BlockInterval(u32::from(u16::MAX) + 1));
+            relative::Height::try_from(BlockInterval(u32::from(u16::MAX) + 1));
         assert!(invalid_height_greater.is_err());
 
-        let valid_height = relative::HeightInterval::try_from(BlockInterval(u32::from(u16::MAX)));
+        let valid_height = relative::Height::try_from(BlockInterval(u32::from(u16::MAX)));
         assert!(valid_height.is_ok());
     }
 
diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs
index 1df4b04c..153aa0e3 100644
--- a/units/src/locktime/absolute.rs
+++ b/units/src/locktime/absolute.rs
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: CC0-1.0
 
-//! Provides [`Height`] and [`Mtp`] types used by the `rust-bitcoin` `absolute::LockTime` type.
+//! Provides [`Height`] and [`Time`] types used by the `rust-bitcoin` `absolute::LockTime` type.
 
 use core::convert::Infallible;
 use core::fmt;
@@ -45,22 +45,15 @@ impl Height {
     /// # Errors
     ///
     /// If the input string is not a valid hex representation of a block height.
-    pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> { parse_hex(s, Self::from_u32) }
-
-    #[deprecated(since = "TBD", note = "use `from_u32` instead")]
-    #[doc(hidden)]
-    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
-
-    #[deprecated(since = "TBD", note = "use `to_u32` instead")]
-    #[doc(hidden)]
-    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
+    pub fn from_hex(s: &str) -> Result<Self, ParseHeightError> {
+        parse_hex(s, Self::from_consensus)
+    }
 
-    /// Constructs a new block height directly from a `u32` value.
+    /// Constructs a new block height.
     ///
     /// # Errors
     ///
-    /// If `n` does not represent a block height within the valid range for a locktime:
-    /// `[0, 499_999_999]`.
+    /// If `n` does not represent a valid block height value.
     ///
     /// # Examples
     ///
@@ -68,11 +61,11 @@ pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
     /// use bitcoin_units::locktime::absolute::Height;
     ///
     /// let h: u32 = 741521;
-    /// let height = Height::from_u32(h).expect("invalid height value");
+    /// let height = Height::from_consensus(h).expect("invalid height value");
     /// assert_eq!(height.to_consensus_u32(), h);
     /// ```
     #[inline]
-    pub const fn from_u32(n: u32) -> Result<Height, ConversionError> {
+    pub const fn from_consensus(n: u32) -> Result<Height, ConversionError> {
         if is_block_height(n) {
             Ok(Self(n))
         } else {
@@ -80,16 +73,16 @@ pub const fn from_u32(n: u32) -> Result<Height, ConversionError> {
         }
     }
 
-    /// Converts this [`Height`] to a raw `u32` value.
+    /// Converts this [`Height`] to its inner `u32` value.
     #[inline]
-    pub const fn to_u32(self) -> u32 { self.0 }
+    pub const fn to_consensus_u32(self) -> u32 { self.0 }
 }
 
 impl fmt::Display for Height {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
-crate::impl_parse_str!(Height, ParseHeightError, parser(Height::from_u32));
+crate::impl_parse_str!(Height, ParseHeightError, parser(Height::from_consensus));
 
 /// Error returned when parsing block height fails.
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -118,7 +111,7 @@ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
         D: serde::Deserializer<'de>,
     {
         let u = u32::deserialize(deserializer)?;
-        Height::from_u32(u).map_err(serde::de::Error::custom)
+        Height::from_consensus(u).map_err(serde::de::Error::custom)
     }
 }
 
@@ -128,69 +121,51 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
-        self.to_u32().serialize(serializer)
+        self.to_consensus_u32().serialize(serializer)
     }
 }
 
-#[deprecated(since = "TBD", note = "use `Mtp` instead")]
-#[doc(hidden)]
-pub type Time = Mtp;
-
-/// The median timestamp of 11 consecutive blocks, representing "the timestamp" of the
-/// final block for locktime-checking purposes.
+/// A UNIX timestamp, seconds since epoch, guaranteed to always contain a valid time value.
 ///
-/// Time-based locktimes are not measured against the timestamps in individual block
-/// headers, since these are not monotone and may be subject to miner manipulation.
-/// Instead, locktimes use the "median-time-past" (MTP) of the most recent 11 blocks,
-/// a quantity which is required by consensus to be monotone and which is difficult
-/// for any individual miner to manipulate.
+/// Note that there is no manipulation of the inner value during construction or when using
+/// `to_consensus_u32()`. Said another way, `Time(x)` means 'x seconds since epoch' _not_ '(x -
+/// threshold) seconds since epoch'.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Mtp(u32);
+pub struct Time(u32);
 
-impl Mtp {
-    /// The minimum MTP allowable in a locktime (Tue Nov 05 1985 00:53:20 GMT+0000).
-    pub const MIN: Self = Mtp(LOCK_TIME_THRESHOLD);
+impl Time {
+    /// The minimum absolute block time (Tue Nov 05 1985 00:53:20 GMT+0000).
+    pub const MIN: Self = Time(LOCK_TIME_THRESHOLD);
 
-    /// The maximum MTP allowable in a locktime (Sun Feb 07 2106 06:28:15 GMT+0000).
-    pub const MAX: Self = Mtp(u32::MAX);
+    /// The maximum absolute block time (Sun Feb 07 2106 06:28:15 GMT+0000).
+    pub const MAX: Self = Time(u32::MAX);
 
-    /// Constructs a new [`Mtp`] from a big-endian hex-encoded `u32`.
+    /// Constructs a new [`Time`] from a hex string.
     ///
     /// The input string may or may not contain a typical hex prefix e.g., `0x`.
     ///
     /// # Errors
     ///
     /// If the input string is not a valid hex representation of a block time.
-    pub fn from_hex(s: &str) -> Result<Self, ParseTimeError> { parse_hex(s, Self::from_u32) }
-
-    #[deprecated(since = "TBD", note = "use `from_u32` instead")]
-    #[doc(hidden)]
-    pub const fn from_consensus(n: u32) -> Result<Self, ConversionError> { Self::from_u32(n) }
+    pub fn from_hex(s: &str) -> Result<Self, ParseTimeError> { parse_hex(s, Self::from_consensus) }
 
-    #[deprecated(since = "TBD", note = "use `to_u32` instead")]
-    #[doc(hidden)]
-    pub const fn to_consensus_u32(self) -> u32 { self.to_u32() }
-
-    /// Constructs a new MTP directly from a `u32` value.
-    ///
-    /// This function, with [`Mtp::to_u32`], is used to obtain a raw MTP value. It is
-    /// **not** used to convert to or from a block timestamp, which is not a MTP.
+    /// Constructs a new block time.
     ///
     /// # Errors
     ///
-    /// If `n` is not in the allowable range of MTPs in a locktime: `[500_000_000, 2^32 - 1]`.
+    /// If `n` does not encode a valid UNIX time stamp.
     ///
     /// # Examples
     ///
     /// ```rust
-    /// use bitcoin_units::locktime::absolute::Mtp;
+    /// use bitcoin_units::locktime::absolute::Time;
     ///
     /// let t: u32 = 1653195600; // May 22nd, 5am UTC.
-    /// let time = Mtp::from_u32(t).expect("invalid time value");
+    /// let time = Time::from_consensus(t).expect("invalid time value");
     /// assert_eq!(time.to_consensus_u32(), t);
     /// ```
     #[inline]
-    pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
+    pub const fn from_consensus(n: u32) -> Result<Time, ConversionError> {
         if is_block_time(n) {
             Ok(Self(n))
         } else {
@@ -198,35 +173,35 @@ pub const fn from_u32(n: u32) -> Result<Self, ConversionError> {
         }
     }
 
-    /// Converts this [`Mtp`] to a raw `u32` value.
+    /// Converts this [`Time`] to its inner `u32` value.
     #[inline]
-    pub const fn to_u32(self) -> u32 { self.0 }
+    pub const fn to_consensus_u32(self) -> u32 { self.0 }
 }
 
-impl fmt::Display for Mtp {
+impl fmt::Display for Time {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
-crate::impl_parse_str!(Mtp, ParseTimeError, parser(Mtp::from_u32));
+crate::impl_parse_str!(Time, ParseTimeError, parser(Time::from_consensus));
 
 #[cfg(feature = "serde")]
-impl<'de> serde::Deserialize<'de> for Mtp {
+impl<'de> serde::Deserialize<'de> for Time {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
         let u = u32::deserialize(deserializer)?;
-        Mtp::from_u32(u).map_err(serde::de::Error::custom)
+        Time::from_consensus(u).map_err(serde::de::Error::custom)
     }
 }
 
 #[cfg(feature = "serde")]
-impl serde::Serialize for Mtp {
+impl serde::Serialize for Time {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: serde::Serializer,
     {
-        self.to_u32().serialize(serializer)
+        self.to_consensus_u32().serialize(serializer)
     }
 }
 
@@ -367,11 +342,11 @@ fn display(
             E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source })
                 if *source.kind() == IntErrorKind::PosOverflow =>
             {
-                // Outputs "failed to parse <input_string> as absolute Height/Mtp (<subject> is above limit <upper_bound>)"
+                // Outputs "failed to parse <input_string> as absolute Height/Time (<subject> is above limit <upper_bound>)"
                 write!(
                     f,
                     "{} ({} is above limit {})",
-                    input.display_cannot_parse("absolute Height/Mtp"),
+                    input.display_cannot_parse("absolute Height/Time"),
                     subject,
                     upper_bound
                 )
@@ -379,17 +354,17 @@ fn display(
             E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source })
                 if *source.kind() == IntErrorKind::NegOverflow =>
             {
-                // Outputs "failed to parse <input_string> as absolute Height/Mtp (<subject> is below limit <lower_bound>)"
+                // Outputs "failed to parse <input_string> as absolute Height/Time (<subject> is below limit <lower_bound>)"
                 write!(
                     f,
                     "{} ({} is below limit {})",
-                    input.display_cannot_parse("absolute Height/Mtp"),
+                    input.display_cannot_parse("absolute Height/Time"),
                     subject,
                     lower_bound
                 )
             }
             E::ParseInt(ParseIntError { input, bits: _, is_signed: _, source: _ }) => {
-                write!(f, "{} ({})", input.display_cannot_parse("absolute Height/Mtp"), subject)
+                write!(f, "{} ({})", input.display_cannot_parse("absolute Height/Time"), subject)
             }
             E::Conversion(value) if *value < i64::from(lower_bound) => {
                 write!(f, "{} {} is below limit {}", subject, value, lower_bound)
@@ -432,27 +407,27 @@ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
             0 => Ok(Height::MIN),
             1 => Ok(Height::MAX),
             _ => {
-                let min = Height::MIN.to_u32();
-                let max = Height::MAX.to_u32();
+                let min = Height::MIN.to_consensus_u32();
+                let max = Height::MAX.to_consensus_u32();
                 let h = u.int_in_range(min..=max)?;
-                Ok(Height::from_u32(h).unwrap())
+                Ok(Height::from_consensus(h).unwrap())
             }
         }
     }
 }
 
 #[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for Mtp {
+impl<'a> Arbitrary<'a> for Time {
     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
         let choice = u.int_in_range(0..=2)?;
         match choice {
-            0 => Ok(Mtp::MIN),
-            1 => Ok(Mtp::MAX),
+            0 => Ok(Time::MIN),
+            1 => Ok(Time::MAX),
             _ => {
-                let min = Mtp::MIN.to_u32();
-                let max = Mtp::MAX.to_u32();
+                let min = Time::MIN.to_consensus_u32();
+                let max = Time::MAX.to_consensus_u32();
                 let t = u.int_in_range(min..=max)?;
-                Ok(Mtp::from_u32(t).unwrap())
+                Ok(Time::from_consensus(t).unwrap())
             }
         }
     }
@@ -467,21 +442,21 @@ mod tests {
 
     #[test]
     fn time_from_str_hex_happy_path() {
-        let actual = Mtp::from_hex("0x6289C350").unwrap();
-        let expected = Mtp::from_u32(0x6289_C350).unwrap();
+        let actual = Time::from_hex("0x6289C350").unwrap();
+        let expected = Time::from_consensus(0x6289_C350).unwrap();
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn time_from_str_hex_no_prefix_happy_path() {
-        let time = Mtp::from_hex("6289C350").unwrap();
-        assert_eq!(time, Mtp(0x6289_C350));
+        let time = Time::from_hex("6289C350").unwrap();
+        assert_eq!(time, Time(0x6289_C350));
     }
 
     #[test]
     fn time_from_str_hex_invalid_hex_should_err() {
         let hex = "0xzb93";
-        let result = Mtp::from_hex(hex);
+        let result = Time::from_hex(hex);
         assert!(result.is_err());
     }
 
@@ -525,18 +500,7 @@ pub fn encode_decode_height() {
     #[test]
     #[cfg(feature = "serde")]
     pub fn encode_decode_time() {
-        serde_round_trip!(Mtp::MIN);
-        serde_round_trip!(Mtp::MAX);
-    }
-
-    #[test]
-    #[cfg(feature = "alloc")]
-    fn locktime_unit_display() {
-        use alloc::format;
-        let blocks = LockTimeUnit::Blocks;
-        let seconds = LockTimeUnit::Seconds;
-
-        assert_eq!(format!("{}", blocks), "expected lock-by-blockheight (must be < 500000000)");
-        assert_eq!(format!("{}", seconds), "expected lock-by-blocktime (must be >= 500000000)");
+        serde_round_trip!(Time::MIN);
+        serde_round_trip!(Time::MAX);
     }
 }
diff --git a/units/src/locktime/relative.rs b/units/src/locktime/relative.rs
index 47dde70a..5736e59e 100644
--- a/units/src/locktime/relative.rs
+++ b/units/src/locktime/relative.rs
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: CC0-1.0
 
-//! Provides [`Height`] and [`MtpInterval`] types used by the `rust-bitcoin` `relative::LockTime` type.
+//! Provides [`Height`] and [`Time`] types used by the `rust-bitcoin` `relative::LockTime` type.
 
 use core::fmt;
 
@@ -11,47 +11,33 @@
 
 use crate::mtp_height::MtpAndHeight;
 
-#[deprecated(since = "TBD", note = "use `HeightIterval` instead")]
-#[doc(hidden)]
-pub type Height = HeightInterval;
-
 /// A relative lock time lock-by-blockheight value.
 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct HeightInterval(u16);
+pub struct Height(u16);
 
-impl HeightInterval {
+impl Height {
     /// Relative block height 0, can be included in any block.
-    pub const ZERO: Self = Self(0);
+    pub const ZERO: Self = Height(0);
 
     /// The minimum relative block height (0), can be included in any block.
     pub const MIN: Self = Self::ZERO;
 
     /// The maximum relative block height.
-    pub const MAX: Self = Self(u16::MAX);
+    pub const MAX: Self = Height(u16::MAX);
 
-    /// Constructs a new [`HeightInterval`] using a count of blocks.
+    /// Constructs a new [`Height`] using a count of blocks.
     #[inline]
-    pub const fn from_height(blocks: u16) -> Self { Self(blocks) }
-
-    /// Express the [`Height`] as a count of blocks.
-    #[inline]
-    #[must_use]
-    pub const fn to_height(self) -> u16 { self.0 }
+    pub const fn from_height(blocks: u16) -> Self { Height(blocks) }
 
     /// Returns the inner `u16` value.
     #[inline]
     #[must_use]
-    #[deprecated(since = "TBD", note = "use `to_height` instead")]
-    #[doc(hidden)]
     pub const fn value(self) -> u16 { self.0 }
 
     /// Returns the `u32` value used to encode this locktime in an nSequence field or
     /// argument to `OP_CHECKSEQUENCEVERIFY`.
-    #[deprecated(
-        since = "TBD",
-        note = "use `LockTime::from` followed by `to_consensus_u32` instead"
-    )]
+    #[inline]
     pub const fn to_consensus_u32(self) -> u32 {
         self.0 as u32 // cast safety: u32 is wider than u16 on all architectures
     }
@@ -70,57 +56,48 @@ pub const fn to_consensus_u32(self) -> u32 {
     pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool {
         // let chain_tip_height = BlockHeight::from(chain_tip);
         // let utxo_mined_at_height = BlockHeight::from(utxo_mined_at);
-        match u32::from(self.to_height()).checked_add(utxo_mined_at.to_height().to_u32()) {
+        match self.to_consensus_u32().checked_add(utxo_mined_at.to_height().to_u32()) {
             Some(target_height) => chain_tip.to_height().to_u32() >= target_height,
             None => false,
         }
     }
 }
 
-impl From<u16> for HeightInterval {
+impl From<u16> for Height {
     #[inline]
-    fn from(value: u16) -> Self { HeightInterval(value) }
+    fn from(value: u16) -> Self { Height(value) }
 }
 
-crate::impl_parse_str_from_int_infallible!(HeightInterval, u16, from);
+crate::impl_parse_str_from_int_infallible!(Height, u16, from);
 
-impl fmt::Display for HeightInterval {
+impl fmt::Display for Height {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
-#[deprecated(since = "TBD", note = "use `Mtp` instead")]
-#[doc(hidden)]
-pub type Time = MtpInterval;
-
 /// A relative lock time lock-by-blocktime value.
 ///
 /// For BIP 68 relative lock-by-blocktime locks, time is measured in 512 second intervals.
 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct MtpInterval(u16);
+pub struct Time(u16);
 
-impl MtpInterval {
+impl Time {
     /// Relative block time 0, can be included in any block.
-    pub const ZERO: Self = MtpInterval(0);
+    pub const ZERO: Self = Time(0);
 
     /// The minimum relative block time (0), can be included in any block.
-    pub const MIN: Self = MtpInterval::ZERO;
+    pub const MIN: Self = Time::ZERO;
 
     /// The maximum relative block time (33,554,432 seconds or approx 388 days).
-    pub const MAX: Self = MtpInterval(u16::MAX);
+    pub const MAX: Self = Time(u16::MAX);
 
-    /// Constructs a new [`MtpInterval`] using time intervals where each interval is equivalent to 512 seconds.
+    /// Constructs a new [`Time`] using time intervals where each interval is equivalent to 512 seconds.
     ///
     /// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin.
     #[inline]
-    pub const fn from_512_second_intervals(intervals: u16) -> Self { MtpInterval(intervals) }
+    pub const fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) }
 
-    /// Express the [`MtpInterval`] as an integer number of 512-second intervals.
-    #[inline]
-    #[must_use]
-    pub const fn to_512_second_intervals(self) -> u16 { self.0 }
-
-    /// Constructs a new [`MtpInterval`] from seconds, converting the seconds into 512 second interval with
+    /// Constructs a new [`Time`] from seconds, converting the seconds into 512 second interval with
     /// truncating division.
     ///
     /// # Errors
@@ -131,13 +108,13 @@ pub const fn to_512_second_intervals(self) -> u16 { self.0 }
     pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError> {
         let interval = seconds / 512;
         if interval <= u16::MAX as u32 { // infallible cast, needed by const code
-            Ok(MtpInterval::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
+            Ok(Time::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
         } else {
             Err(TimeOverflowError { seconds })
         }
     }
 
-    /// Constructs a new [`MtpInterval`] from seconds, converting the seconds into 512 second intervals with
+    /// Constructs a new [`Time`] from seconds, converting the seconds into 512 second intervals with
     /// ceiling division.
     ///
     /// # Errors
@@ -148,7 +125,7 @@ pub const fn from_seconds_floor(seconds: u32) -> Result<Self, TimeOverflowError>
     pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError> {
         if seconds <= u16::MAX as u32 * 512 {
             let interval = (seconds + 511) / 512;
-            Ok(MtpInterval::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
+            Ok(Time::from_512_second_intervals(interval as u16)) // Cast checked above, needed by const code.
         } else {
             Err(TimeOverflowError { seconds })
         }
@@ -157,16 +134,11 @@ pub const fn from_seconds_ceil(seconds: u32) -> Result<Self, TimeOverflowError>
     /// Returns the inner `u16` value.
     #[inline]
     #[must_use]
-    #[deprecated(since = "TBD", note = "use `to_512_second_intervals` instead")]
-    #[doc(hidden)]
     pub const fn value(self) -> u16 { self.0 }
 
     /// Returns the `u32` value used to encode this locktime in an nSequence field or
     /// argument to `OP_CHECKSEQUENCEVERIFY`.
-    #[deprecated(
-        since = "TBD",
-        note = "use `LockTime::from` followed by `to_consensus_u32` instead"
-    )]
+    #[inline]
     pub const fn to_consensus_u32(self) -> u32 {
         (1u32 << 22) | self.0 as u32 // cast safety: u32 is wider than u16 on all architectures
     }
@@ -183,7 +155,7 @@ pub const fn to_consensus_u32(self) -> u32 {
     /// - `true` if the relative‐time lock has expired by the tip’s MTP
     /// - `false` if the lock has not yet expired by the tip’s MTP
     pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeight) -> bool {
-        match u32::from(self.to_512_second_intervals()).checked_mul(512) {
+        match u32::from(self.value()).checked_mul(512) {
             Some(seconds) => match seconds.checked_add(utxo_mined_at.to_mtp().to_u32()) {
                 Some(required_seconds) => chain_tip.to_mtp().to_u32() >= required_seconds,
                 None => false,
@@ -193,16 +165,16 @@ pub fn is_satisfied_by(self, chain_tip: MtpAndHeight, utxo_mined_at: MtpAndHeigh
     }
 }
 
-crate::impl_parse_str_from_int_infallible!(MtpInterval, u16, from_512_second_intervals);
+crate::impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
 
-impl fmt::Display for MtpInterval {
+impl fmt::Display for Time {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
 }
 
 /// Error returned when the input time in seconds was too large to be encoded to a 16 bit 512 second interval.
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TimeOverflowError {
-    /// Time interval value in seconds that overflowed.
+    /// Time value in seconds that overflowed.
     // Private because we maintain an invariant that the `seconds` value does actually overflow.
     pub(crate) seconds: u32,
 }
@@ -233,27 +205,27 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl std::error::Error for TimeOverflowError {}
 
 #[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for HeightInterval {
+impl<'a> Arbitrary<'a> for Height {
     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
         let choice = u.int_in_range(0..=2)?;
 
         match choice {
-            0 => Ok(HeightInterval::MIN),
-            1 => Ok(HeightInterval::MAX),
-            _ => Ok(HeightInterval::from_height(u16::arbitrary(u)?)),
+            0 => Ok(Height::MIN),
+            1 => Ok(Height::MAX),
+            _ => Ok(Height::from_height(u16::arbitrary(u)?)),
         }
     }
 }
 
 #[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for MtpInterval {
+impl<'a> Arbitrary<'a> for Time {
     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
         let choice = u.int_in_range(0..=2)?;
 
         match choice {
-            0 => Ok(MtpInterval::MIN),
-            1 => Ok(MtpInterval::MAX),
-            _ => Ok(MtpInterval::from_512_second_intervals(u16::arbitrary(u)?)),
+            0 => Ok(Time::MIN),
+            1 => Ok(Time::MAX),
+            _ => Ok(Time::from_512_second_intervals(u16::arbitrary(u)?)),
         }
     }
 }
@@ -269,74 +241,73 @@ mod tests {
     const MAXIMUM_ENCODABLE_SECONDS: u32 = u16::MAX as u32 * 512;
 
     #[test]
-    #[allow(deprecated_in_future)]
     fn sanity_check() {
-        assert_eq!(HeightInterval::MAX.to_consensus_u32(), u32::from(u16::MAX));
-        assert_eq!(MtpInterval::from_512_second_intervals(100).value(), 100u16);
-        assert_eq!(MtpInterval::from_512_second_intervals(100).to_consensus_u32(), 4_194_404u32); // 0x400064
+        assert_eq!(Height::MAX.to_consensus_u32(), u32::from(u16::MAX));
+        assert_eq!(Time::from_512_second_intervals(100).value(), 100u16);
+        assert_eq!(Time::from_512_second_intervals(100).to_consensus_u32(), 4_194_404u32); // 0x400064
     }
 
     #[test]
     fn from_seconds_ceil_success() {
-        let actual = MtpInterval::from_seconds_ceil(100).unwrap();
-        let expected = MtpInterval(1_u16);
+        let actual = Time::from_seconds_ceil(100).unwrap();
+        let expected = Time(1_u16);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_ceil_with_maximum_encodable_seconds_success() {
-        let actual = MtpInterval::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
-        let expected = MtpInterval(u16::MAX);
+        let actual = Time::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS).unwrap();
+        let expected = Time(u16::MAX);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_ceil_causes_time_overflow_error() {
-        let result = MtpInterval::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
+        let result = Time::from_seconds_ceil(MAXIMUM_ENCODABLE_SECONDS + 1);
         assert!(result.is_err());
     }
 
     #[test]
     fn from_seconds_floor_success() {
-        let actual = MtpInterval::from_seconds_floor(100).unwrap();
-        let expected = MtpInterval(0_u16);
+        let actual = Time::from_seconds_floor(100).unwrap();
+        let expected = Time(0_u16);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_floor_with_exact_interval() {
-        let actual = MtpInterval::from_seconds_floor(512).unwrap();
-        let expected = MtpInterval(1_u16);
+        let actual = Time::from_seconds_floor(512).unwrap();
+        let expected = Time(1_u16);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_floor_with_maximum_encodable_seconds_success() {
-        let actual = MtpInterval::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
-        let expected = MtpInterval(u16::MAX);
+        let actual = Time::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 511).unwrap();
+        let expected = Time(u16::MAX);
         assert_eq!(actual, expected);
     }
 
     #[test]
     fn from_seconds_floor_causes_time_overflow_error() {
-        let result = MtpInterval::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
+        let result = Time::from_seconds_floor(MAXIMUM_ENCODABLE_SECONDS + 512);
         assert!(result.is_err());
     }
 
     #[test]
     #[cfg(feature = "serde")]
     pub fn encode_decode_height() {
-        serde_round_trip!(HeightInterval::ZERO);
-        serde_round_trip!(HeightInterval::MIN);
-        serde_round_trip!(HeightInterval::MAX);
+        serde_round_trip!(Height::ZERO);
+        serde_round_trip!(Height::MIN);
+        serde_round_trip!(Height::MAX);
     }
 
     #[test]
     #[cfg(feature = "serde")]
     pub fn encode_decode_time() {
-        serde_round_trip!(MtpInterval::ZERO);
-        serde_round_trip!(MtpInterval::MIN);
-        serde_round_trip!(MtpInterval::MAX);
+        serde_round_trip!(Time::ZERO);
+        serde_round_trip!(Time::MIN);
+        serde_round_trip!(Time::MAX);
     }
 
     fn generate_timestamps(start: u32, step: u16) -> [BlockTime; 11] {
@@ -360,7 +331,7 @@ fn test_time_chain_state() {
 
         // Test case 1: Satisfaction (current_mtp >= utxo_mtp + required_seconds)
         // 10 intervals × 512 seconds = 5120 seconds
-        let time_lock = MtpInterval::from_512_second_intervals(10);
+        let time_lock = Time::from_512_second_intervals(10);
         let chain_state1 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
         let utxo_state1 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
         assert!(time_lock.is_satisfied_by(chain_state1, utxo_state1));
@@ -371,13 +342,13 @@ fn test_time_chain_state() {
         assert!(!time_lock.is_satisfied_by(chain_state2, utxo_state2));
 
         // Test case 3: Test with a larger value (100 intervals = 51200 seconds)
-        let larger_lock = MtpInterval::from_512_second_intervals(100);
+        let larger_lock = Time::from_512_second_intervals(100);
         let chain_state3 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps3);
         let utxo_state3 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps3);
         assert!(larger_lock.is_satisfied_by(chain_state3, utxo_state3));
 
         // Test case 4: Overflow handling - tests that is_satisfied_by handles overflow gracefully
-        let max_time_lock = MtpInterval::MAX;
+        let max_time_lock = Time::MAX;
         let chain_state4 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
         let utxo_state4 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
         assert!(!max_time_lock.is_satisfied_by(chain_state4, utxo_state4));
@@ -388,7 +359,7 @@ fn test_height_chain_state() {
         let timestamps: [BlockTime; 11] = generate_timestamps(1_600_000_000, 200);
         let utxo_timestamps: [BlockTime; 11] = generate_timestamps(1_599_000_000, 200);
 
-        let height_lock = HeightInterval(10);
+        let height_lock = Height(10);
 
         // Test case 1: Satisfaction (current_height >= utxo_height + required)
         let chain_state1 = MtpAndHeight::new(BlockHeight::from_u32(100), timestamps);
@@ -401,7 +372,7 @@ fn test_height_chain_state() {
         assert!(!height_lock.is_satisfied_by(chain_state2, utxo_state2));
 
         // Test case 3: Overflow handling - tests that is_satisfied_by handles overflow gracefully
-        let max_height_lock = HeightInterval::MAX;
+        let max_height_lock = Height::MAX;
         let chain_state3 = MtpAndHeight::new(BlockHeight::from_u32(1000), timestamps);
         let utxo_state3 = MtpAndHeight::new(BlockHeight::from_u32(80), utxo_timestamps);
         assert!(!max_height_lock.is_satisfied_by(chain_state3, utxo_state3));


Test patch:
diff --git a/bitcoin/tests/bip_174.rs b/bitcoin/tests/bip_174.rs
index 10fb81ac..ee7a8470 100644
--- a/bitcoin/tests/bip_174.rs
+++ b/bitcoin/tests/bip_174.rs
@@ -122,7 +122,7 @@ fn build_extended_private_key() -> Xpriv {
     let xpriv = extended_private_key.parse::<Xpriv>().unwrap();
 
     let sk = PrivateKey::from_wif(seed).unwrap();
-    let seeded = Xpriv::new_master(NetworkKind::Test, &sk.inner.secret_bytes());
+    let seeded = Xpriv::new_master(NetworkKind::Test, &sk.inner.secret_bytes()).unwrap();
     assert_eq!(xpriv, seeded);
 
     xpriv
@@ -317,8 +317,7 @@ fn parse_and_verify_keys(
 
         let path =
             derivation_path.into_derivation_path().expect("failed to convert derivation path");
-        let derived_priv =
-            ext_priv.derive_xpriv(secp, &path).expect("derivation path too long").to_private_key();
+        let derived_priv = ext_priv.derive_xpriv(secp, &path).to_private_key();
         assert_eq!(wif_priv, derived_priv);
         let derived_pub = derived_priv.public_key(secp);
         key_map.insert(derived_pub, derived_priv);
diff --git a/units/src/amount/tests.rs b/units/src/amount/tests.rs
index 61e2e998..a9b19c13 100644
--- a/units/src/amount/tests.rs
+++ b/units/src/amount/tests.rs
@@ -13,9 +13,9 @@
 use ::serde::{Deserialize, Serialize};
 
 use super::*;
+use crate::NumOpResult;
 #[cfg(feature = "alloc")]
 use crate::{FeeRate, Weight};
-use crate::{MathOp, NumOpResult};
 
 #[track_caller]
 fn sat(sat: u64) -> Amount { Amount::from_sat(sat).unwrap() }
@@ -120,75 +120,6 @@ fn from_int_btc() {
     assert_eq!(ssat(-200_000_000), amt);
 }
 
-#[test]
-#[cfg(feature = "alloc")]
-fn display_display_struct() {
-    let display_fixed_btc = Display {
-        sats_abs: 100_000_000,
-        is_negative: false,
-        style: DisplayStyle::FixedDenomination {
-            denomination: Denomination::Bitcoin,
-            show_denomination: true,
-        },
-    };
-    assert_eq!(format!("{}", display_fixed_btc), "1 BTC");
-
-    let display_fixed_sat = Display {
-        sats_abs: 1,
-        is_negative: false,
-        style: DisplayStyle::FixedDenomination {
-            denomination: Denomination::Satoshi,
-            show_denomination: true,
-        },
-    };
-    assert_eq!(format!("{}", display_fixed_sat), "1 satoshi");
-
-    let display_dynamic_btc = Display {
-        sats_abs: 100_000_000,
-        is_negative: false,
-        style: DisplayStyle::DynamicDenomination,
-    };
-    assert_eq!(format!("{}", display_dynamic_btc), "1 BTC");
-
-    let display_dynamic_sat = Display {
-        sats_abs: 99_999_999,
-        is_negative: false,
-        style: DisplayStyle::DynamicDenomination,
-    };
-    assert_eq!(format!("{}", display_dynamic_sat), "99999999 satoshi");
-
-    let display_negative_btc = Display {
-        sats_abs: 100_000_000,
-        is_negative: true,
-        style: DisplayStyle::DynamicDenomination,
-    };
-    assert_eq!(format!("{}", display_negative_btc), "-1 BTC");
-
-    let display_negative_sat = Display {
-        sats_abs: 99_999_999,
-        is_negative: true,
-        style: DisplayStyle::DynamicDenomination,
-    };
-    assert_eq!(format!("{}", display_negative_sat), "-99999999 satoshi");
-}
-
-#[test]
-#[cfg(feature = "alloc")]
-fn display_math_op() {
-    let cases = [
-        (MathOp::Add, "add"),
-        (MathOp::Sub, "sub"),
-        (MathOp::Mul, "mul"),
-        (MathOp::Div, "div"),
-        (MathOp::Rem, "rem"),
-        (MathOp::Neg, "neg"),
-    ];
-
-    for (op, expected) in cases {
-        assert_eq!(format!("{}", op), expected);
-    }
-}
-
 #[test]
 fn amount_try_from_signed_amount() {
     let sa_positive = ssat(123);
diff --git a/units/tests/api.rs b/units/tests/api.rs
index 41b39bb4..46a16e42 100644
--- a/units/tests/api.rs
+++ b/units/tests/api.rs
@@ -38,7 +38,7 @@ struct Structs {
     e: BlockInterval,
     f: FeeRate,
     g: absolute::Height,
-    h: absolute::Mtp,
+    h: absolute::Time,
     i: relative::Height,
     j: relative::Time,
     k: Weight,
@@ -55,7 +55,7 @@ fn max() -> Self {
             e: BlockInterval::MAX,
             f: FeeRate::MAX,
             g: absolute::Height::MAX,
-            h: absolute::Mtp::MAX,
+            h: absolute::Time::MAX,
             i: relative::Height::MAX,
             j: relative::Time::MAX,
             k: Weight::MAX,
@@ -85,7 +85,7 @@ struct CommonTraits {
     e: BlockInterval,
     f: FeeRate,
     g: absolute::Height,
-    h: absolute::Mtp,
+    h: absolute::Time,
     i: relative::Height,
     j: relative::Time,
     k: Weight,
@@ -128,7 +128,7 @@ struct Errors {
     t: amount::PossiblyConfusingDenominationError,
     u: amount::TooPreciseError,
     v: amount::UnknownDenominationError,
-    w: block::TooBigForRelativeBlockHeightIntervalError,
+    w: block::TooBigForRelativeBlockHeightError,
     x: locktime::absolute::ConversionError,
     y: locktime::absolute::Height,
     z: locktime::absolute::ParseHeightError,
@@ -163,9 +163,7 @@ fn api_can_use_all_types_from_module_amount() {
 
 #[test]
 fn api_can_use_all_types_from_module_block() {
-    use bitcoin_units::block::{
-        BlockHeight, BlockInterval, TooBigForRelativeBlockHeightIntervalError,
-    };
+    use bitcoin_units::block::{BlockHeight, BlockInterval, TooBigForRelativeBlockHeightError};
 }
 
 #[test]
@@ -176,7 +174,7 @@ fn api_can_use_all_types_from_module_fee_rate() {
 #[test]
 fn api_can_use_all_types_from_module_locktime_absolute() {
     use bitcoin_units::locktime::absolute::{
-        ConversionError, Height, Mtp, ParseHeightError, ParseTimeError,
+        ConversionError, Height, ParseHeightError, ParseTimeError, Time,
     };
 }
 
@@ -293,7 +291,7 @@ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
             e: BlockInterval::arbitrary(u)?,
             f: FeeRate::arbitrary(u)?,
             g: absolute::Height::arbitrary(u)?,
-            h: absolute::Mtp::arbitrary(u)?,
+            h: absolute::Time::arbitrary(u)?,
             i: relative::Height::arbitrary(u)?,
             j: relative::Time::arbitrary(u)?,
             k: Weight::arbitrary(u)?,
diff --git a/units/tests/serde.rs b/units/tests/serde.rs
index 24cf9b04..d807bcc7 100644
--- a/units/tests/serde.rs
+++ b/units/tests/serde.rs
@@ -47,7 +47,7 @@ struct Serde {
     a: BlockHeight,
     b: BlockInterval,
     c: absolute::Height,
-    d: absolute::Mtp,
+    d: absolute::Time,
     e: relative::Height,
     f: relative::Time,
     g: Weight,
@@ -80,7 +80,7 @@ fn new() -> Self {
             a: BlockHeight::MAX,
             b: BlockInterval::MAX,
             c: absolute::Height::MAX,
-            d: absolute::Mtp::MAX,
+            d: absolute::Time::MAX,
             e: relative::Height::MAX,
             f: relative::Time::MAX,
             g: Weight::MAX,
diff --git a/units/tests/str.rs b/units/tests/str.rs
index 20d6013e..0b365af2 100644
--- a/units/tests/str.rs
+++ b/units/tests/str.rs
@@ -2,7 +2,6 @@
 
 //! Do basic regression tests on the `Display` and `FromStr` impls.
 
-use bitcoin_units::amount::Denomination;
 use bitcoin_units::locktime::{absolute, relative};
 use bitcoin_units::{Amount, BlockHeight, BlockInterval, FeeRate, SignedAmount, Weight};
 
@@ -25,9 +24,6 @@ fn $test_name() {
     amount_unsigned_one_sat, Amount, Amount::ONE_SAT, "0.00000001 BTC";
     amount_unsigned_max_money, Amount, Amount::MAX, "21000000 BTC";
 
-    denomination_btc, Denomination, Denomination::BTC, "BTC";
-    denomination_sat, Denomination, Denomination::SAT, "satoshi";
-
     amount_signed_one_sat, SignedAmount, SignedAmount::ONE_SAT, "0.00000001 BTC";
     amount_signed_max_money, SignedAmount, SignedAmount::MAX, "21000000 BTC";
 
@@ -41,17 +37,11 @@ fn $test_name() {
     fee_rate_max, FeeRate, FeeRate::MAX, "18446744073709551615";
     fee_rate_dust, FeeRate, FeeRate::DUST, "750";
 
-    lock_by_height_absolute_min, absolute::Height, absolute::Height::MIN, "0";
-    lock_by_height_absolute_max, absolute::Height, absolute::Height::MAX, "499999999";
-
-    lock_by_height_relative_min, relative::Height, relative::Height::MIN, "0";
-    lock_by_height_relative_max, relative::Height, relative::Height::MAX, "65535";
-
-    lock_by_time_absolute_min, absolute::Time, absolute::Time::MIN, "500000000";
-    lock_by_time_absolute_max, absolute::Time, absolute::Time::MAX, "4294967295";
+    lock_time_absolute_min, absolute::Height, absolute::Height::MIN, "0";
+    lock_time_absolute_max, absolute::Height, absolute::Height::MAX, "499999999";
 
-    lock_by_time_relative_min, relative::Time, relative::Time::MIN, "0";
-    lock_by_time_relative_max, relative::Time, relative::Time::MAX, "65535";
+    lock_time_relative_min, relative::Height, relative::Height::MIN, "0";
+    lock_time_relative_max, relative::Height, relative::Height::MAX, "65535";
 
     weight_min, Weight, Weight::MIN, "0";
     weight_max, Weight, Weight::MAX, "18446744073709551615";