From f268ca20c5855c751df76eaaff333e31408a4d9e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 5 Feb 2025 14:37:57 +1100 Subject: [PATCH] hashes: Add api test file As we did for `units` and as part of the stabalization effort. Add an `api` test module that verifies the public API for the `hashes` crate. --- hashes/tests/api.rs | 225 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 hashes/tests/api.rs diff --git a/hashes/tests/api.rs b/hashes/tests/api.rs new file mode 100644 index 000000000..5de01d551 --- /dev/null +++ b/hashes/tests/api.rs @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Test the API surface of `units`. +//! +//! The point of these tests are to check the API surface as opposed to test the API functionality. +//! +//! ref: + +#![allow(dead_code)] +#![allow(unused_imports)] + +// Import using module style e.g., `sha256::Hash`. +use bitcoin_hashes::{ + hash160, hash_newtype, hkdf, hmac, ripemd160, sha1, sha256, sha256d, sha256t, sha256t_tag, + sha384, sha512, sha512_256, siphash24, FromSliceError, Hash, HashEngine, +}; +// Import using type alias style e.g., `Sha256`. +use bitcoin_hashes::{ + Hash160, Hkdf, Hmac, HmacEngine, Ripemd160, Sha1, Sha256, Sha256d, Sha256t, Sha384, Sha512, + Sha512_256, Siphash24, +}; + +// Arbitrary midstate value; taken from as sha256t unit tests. +const TEST_MIDSTATE: [u8; 32] = [ + 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108, + 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201, +]; + +sha256t_tag! { + /// Test tag so we don't have to use generics. + #[derive(Debug)] + struct Tag = raw(TEST_MIDSTATE, 64); +} +hash_newtype! { + /// A concrete sha256t hash type so we don't have to use generics. + #[derive(Debug)] + struct TaggedHash(sha256t::Hash); +} + +/// All the hash types excluding `Hkdf`. +// `Hkdf` only implements `Copy` and `Clone` ATM - by design. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] // C-COMMON-TRAITS +// We check `Hkdf` implements `Debug` in the non-empty debug test below. +#[derive(Debug)] // All public types implement Debug (C-DEBUG). +struct Hashes { + a: hash160::Hash, + c: Hmac, + d: ripemd160::Hash, + e: sha1::Hash, + f: sha256::Hash, + g: sha256d::Hash, + h: TaggedHash, + i: sha384::Hash, + j: sha512::Hash, + k: sha512_256::Hash, + l: siphash24::Hash, +} + +impl Hashes { + fn new_sha256() -> Self { + let hmac = HmacEngine::::new(&[]).finalize(); + // `TaggedHash` is not a general hash but `Sha256` is. + let tagged = TaggedHash::from_byte_array(Sha256t::::hash(&[]).to_byte_array()); + let siphash = Siphash24::from_engine(siphash24::HashEngine::with_keys(0, 0)); + + Hashes { + a: Hash160::hash(&[]), + // b: hkdf, + c: hmac, + d: Ripemd160::hash(&[]), + e: Sha1::hash(&[]), + f: Sha256::hash(&[]), + g: Sha256d::hash(&[]), + h: tagged, + i: Sha384::hash(&[]), + j: Sha512::hash(&[]), + k: Sha512_256::hash(&[]), + l: siphash, + } + } +} + +/// All the hash engines. +#[derive(Clone)] // C-COMMON-TRAITS +#[derive(Debug)] // All public types implement Debug (C-DEBUG). +struct Engines { + a: hash160::HashEngine, + // We cannot derive `Debug` on a generic `HmacEngine` engine. + b: hmac::HmacEngine, + c: ripemd160::HashEngine, + d: sha1::HashEngine, + e: sha256::HashEngine, + f: sha256d::HashEngine, + g: sha256t::HashEngine, + h: sha384::HashEngine, + i: sha512::HashEngine, + j: sha512_256::HashEngine, + k: siphash24::HashEngine, +} + +impl Engines { + fn new_sha256() -> Self { + Engines { + a: hash160::HashEngine::new(), + b: hmac::HmacEngine::::new(&[]), + c: ripemd160::HashEngine::new(), + d: sha1::HashEngine::new(), + e: sha256::HashEngine::new(), + f: sha256d::HashEngine::new(), + g: sha256t::Hash::::engine(), + h: sha384::HashEngine::new(), + i: sha512::HashEngine::new(), + j: sha512_256::HashEngine::new(), + k: siphash24::HashEngine::with_keys(0, 0), + } + } +} + +/// Public structs that are not hashes, engines, or errors. +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] // C-COMMON-TRAITS +#[derive(Debug)] // All public types implement Debug (C-DEBUG). +struct OtherStructs { + a: sha256::Midstate, + // There is no way to construct a `siphash24::State` so we cannot directly + // test it but `siphash24::HashEngine` includes one so `Engines` implicitly + // tests it (e.g. `Debug` and `Clone`). + // + // b: siphash24::State, + + // Don't worry about including a tag because its tested in `primitives`. +} + +impl OtherStructs { + fn new() -> Self { Self { a: sha256::Midstate::new(TEST_MIDSTATE, 0) } } +} + +/// All hash engine types that implement `Default`. +#[derive(Default)] +struct Default { + a: hash160::HashEngine, + b: ripemd160::HashEngine, + c: sha1::HashEngine, + d: sha256::HashEngine, + e: sha256d::HashEngine, + f: sha256t::HashEngine, + g: sha384::HashEngine, + h: sha512::HashEngine, + i: sha512_256::HashEngine, +} + +/// Hash types that require a key. +struct Keyed { + a: Hmac, + l: siphash24::Hash, +} + +/// A struct that includes all public error types. +// These derives are the policy of `rust-bitcoin` not Rust API guidelines. +#[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG). +struct Errors { + a: FromSliceError, + b: hkdf::MaxLengthError, + c: sha256::MidstateError, +} + +#[test] +fn api_can_use_modules_from_crate_root() { + use bitcoin_hashes::{ + hash160, hkdf, hmac, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, + siphash24, + }; +} + +#[test] +fn api_can_use_alias_from_crate_root() { + use bitcoin_hashes::{ + Hash160, Hkdf, Hmac, Ripemd160, Sha1, Sha256, Sha256d, Sha256t, Sha384, Sha512, Sha512_256, + Siphash24, + }; +} + +// `Debug` representation is never empty (C-DEBUG-NONEMPTY). +#[test] +fn api_all_non_error_types_have_non_empty_debug() { + macro_rules! check_debug { + ($t:tt; $($field:tt),* $(,)?) => { + $( + let debug = format!("{:?}", $t.$field); + assert!(!debug.is_empty()); + )* + } + } + + let t = Hashes::::new_sha256(); + check_debug!(t; a, c, d, e, f, g, h, i, j, k, l); + + // This tests `Debug` on `Hkdf` but not for all `T: GeneralHash`. + let t = Hkdf::::new(&[], &[]); + let debug = format!("{:?}", t); + assert!(!debug.is_empty()); + + let t = Engines::new_sha256(); + check_debug!(t; a, c, d, e, f, g, h, i, j, k); + + let t = OtherStructs::new(); + check_debug!(t; a); +} + +#[test] +fn all_types_implement_send_sync() { + fn assert_send() {} + fn assert_sync() {} + + // Types are `Send` and `Sync` where possible (C-SEND-SYNC). + assert_send::>(); + assert_sync::>(); + assert_send::(); + assert_sync::(); + assert_send::(); + assert_sync::(); + + // Error types should implement the Send and Sync traits (C-GOOD-ERR). + assert_send::(); + assert_sync::(); +}