use super::{DIGEST_LENGTH, Digest};
#[cfg(all(target_arch = "aarch64", any(target_feature = "sha2", feature = "std")))]
mod aarch64;
#[cfg(all(
target_arch = "x86_64",
any(
all(
target_feature = "sha",
target_feature = "avx2",
target_feature = "ssse3",
target_feature = "sse4.1",
),
feature = "std",
),
))]
mod x86_64;
const POSITION_LEN: usize = 8;
const MMR_NODE_LEN: usize = POSITION_LEN + 2 * DIGEST_LENGTH;
const _: () = assert!(MMR_NODE_LEN == 72);
const BMT_NODE_LEN: usize = 2 * DIGEST_LENGTH;
const _: () = assert!(BMT_NODE_LEN == 64);
#[inline(always)]
pub(super) fn hash_pair(left: &[&[u8]], right: &[&[u8]]) -> Option<(Digest, Digest)> {
match (left, right) {
([left_pos, left_left, left_right], [right_pos, right_left, right_right]) => dispatch_mmr(
(*left_pos).try_into().ok()?,
(*left_left).try_into().ok()?,
(*left_right).try_into().ok()?,
(*right_pos).try_into().ok()?,
(*right_left).try_into().ok()?,
(*right_right).try_into().ok()?,
),
([left_a, left_b], [right_a, right_b]) => dispatch_bmt(
(*left_a).try_into().ok()?,
(*left_b).try_into().ok()?,
(*right_a).try_into().ok()?,
(*right_b).try_into().ok()?,
),
_ => None,
}
}
macro_rules! define_dispatch {
($name:ident, $aarch64_kernel:ident, $x86_64_kernel:ident, ($($arg:ident: $ty:ty),+ $(,)?)) => {
#[inline(always)]
fn $name($($arg: $ty),+) -> Option<(Digest, Digest)> {
cfg_if::cfg_if! {
if #[cfg(all(target_arch = "aarch64", target_feature = "sha2"))] {
Some(unsafe { aarch64::$aarch64_kernel($($arg),+) })
} else if #[cfg(all(target_arch = "aarch64", feature = "std"))] {
if std::arch::is_aarch64_feature_detected!("sha2") {
return Some(unsafe { aarch64::$aarch64_kernel($($arg),+) });
}
None
} else if #[cfg(all(
target_arch = "x86_64",
target_feature = "sha",
target_feature = "avx2",
target_feature = "ssse3",
target_feature = "sse4.1",
))] {
Some(unsafe { x86_64::$x86_64_kernel($($arg),+) })
} else if #[cfg(all(target_arch = "x86_64", feature = "std"))] {
if std::arch::is_x86_feature_detected!("sha")
&& std::arch::is_x86_feature_detected!("avx2")
&& std::arch::is_x86_feature_detected!("ssse3")
&& std::arch::is_x86_feature_detected!("sse4.1")
{
return Some(unsafe { x86_64::$x86_64_kernel($($arg),+) });
}
None
} else {
let _ = ($($arg),+);
None
}
}
}
};
}
define_dispatch!(
dispatch_mmr,
hash_pair_72,
hash_pair_72,
(
left_pos: &[u8; POSITION_LEN],
left_left: &[u8; DIGEST_LENGTH],
left_right: &[u8; DIGEST_LENGTH],
right_pos: &[u8; POSITION_LEN],
right_left: &[u8; DIGEST_LENGTH],
right_right: &[u8; DIGEST_LENGTH],
)
);
define_dispatch!(
dispatch_bmt,
hash_pair_64,
hash_pair_64,
(
left_a: &[u8; DIGEST_LENGTH],
left_b: &[u8; DIGEST_LENGTH],
right_a: &[u8; DIGEST_LENGTH],
right_b: &[u8; DIGEST_LENGTH],
)
);