#[inline(always)]
#[must_use]
pub(super) const fn rapid_mum_np<const PROTECTED: bool>(a: u64, b: u64) -> (u64, u64) {
#[cfg(any(
all(
target_pointer_width = "64",
not(any(target_arch = "sparc64", target_arch = "wasm64")),
),
target_arch = "aarch64",
target_arch = "x86_64",
all(target_family = "wasm", target_feature = "wide-arithmetic"),
))]
{
let r = (a as u128).wrapping_mul(b as u128);
if !PROTECTED {
(r as u64, (r >> 64) as u64)
} else {
(a ^ r as u64, b ^ (r >> 64) as u64)
}
}
#[cfg(not(any(
all(
target_pointer_width = "64",
not(any(target_arch = "sparc64", target_arch = "wasm64")),
),
target_arch = "aarch64",
target_arch = "x86_64",
all(target_family = "wasm", target_feature = "wide-arithmetic"),
)))]
{
let lx = a as u32;
let ly = b as u32;
let hx = (a >> 32) as u32;
let hy = (b >> 32) as u32;
let ll = (lx as u64).wrapping_mul(ly as u64);
let lh = (lx as u64).wrapping_mul(hy as u64);
let hl = (hx as u64).wrapping_mul(ly as u64);
let hh = (hx as u64).wrapping_mul(hy as u64);
if !PROTECTED {
((hh ^ ll), (hl ^ lh).rotate_right(32))
} else {
((a ^ hh ^ ll), (b ^ hl ^ lh).rotate_right(32))
}
}
}
#[inline(always)]
#[must_use]
pub(super) const fn rapid_mix_np<const PROTECTED: bool>(a: u64, b: u64) -> u64 {
#[cfg(any(
all(
target_pointer_width = "64",
not(any(target_arch = "sparc64", target_arch = "wasm64")),
),
target_arch = "aarch64",
target_arch = "x86_64",
all(target_family = "wasm", target_feature = "wide-arithmetic"),
))]
{
let r = (a as u128).wrapping_mul(b as u128);
if !PROTECTED {
(r as u64) ^ (r >> 64) as u64
} else {
(a ^ r as u64) ^ (b ^ (r >> 64) as u64)
}
}
#[cfg(not(any(
all(
target_pointer_width = "64",
not(any(target_arch = "sparc64", target_arch = "wasm64")),
),
target_arch = "aarch64",
target_arch = "x86_64",
all(target_family = "wasm", target_feature = "wide-arithmetic"),
)))]
{
let lx = a as u32;
let ly = b as u32;
let hx = (a >> 32) as u32;
let hy = (b >> 32) as u32;
let ll = (lx as u64).wrapping_mul(ly as u64);
let lh = (lx as u64).wrapping_mul(hy as u64);
let hl = (hx as u64).wrapping_mul(ly as u64);
let hh = (hx as u64).wrapping_mul(hy as u64);
if !PROTECTED {
(hh ^ ll) ^ (hl ^ lh).rotate_right(32)
} else {
(a ^ hh ^ ll) ^ (b ^ hl ^ lh).rotate_right(32)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(any(
all(
target_pointer_width = "64",
not(any(target_arch = "sparc64", target_arch = "wasm64")),
),
target_arch = "aarch64",
target_arch = "x86_64",
all(target_family = "wasm", target_feature = "wide-arithmetic"),
))]
fn test_rapid_mum() {
let (a, b) = rapid_mum_np::<false>(0, 0);
assert_eq!(a, 0);
assert_eq!(b, 0);
let (a, b) = rapid_mum_np::<false>(100, 100);
assert_eq!(a, 10000);
assert_eq!(b, 0);
let (a, b) = rapid_mum_np::<false>(u64::MAX, 2);
assert_eq!(a, u64::MAX - 1);
assert_eq!(b, 1);
}
}