From 44ab5507351966695c525fab4835092b34b197a3 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 27 Aug 2026 15:58:05 -0600 Subject: [PATCH] polyval: add `FieldElement::divx` This is useful for writing a generalized `FieldElement` type for the `ghash` crate, specifically when converting from a POLYVAL field element back to a GHASH one. --- Cargo.lock | 4 ++-- polyval/src/field_element/mulx.rs | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e93ee6..529fc38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,9 +49,9 @@ checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" [[package]] name = "cpufeatures" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] diff --git a/polyval/src/field_element/mulx.rs b/polyval/src/field_element/mulx.rs index fb54b8e..9ede7d9 100644 --- a/polyval/src/field_element/mulx.rs +++ b/polyval/src/field_element/mulx.rs @@ -5,7 +5,7 @@ use super::FieldElement; impl FieldElement { /// The `mulX_POLYVAL()` function as defined in [RFC 8452 Appendix A][1]. /// - /// Performs a doubling (a.k.a. "multiply by x") over GF(2^128). + /// Performs a doubling (a.k.a. "multiply-by-x") over GF(2^128). /// This is useful for implementing GHASH in terms of POLYVAL. /// /// [1]: https://tools.ietf.org/html/rfc8452#appendix-A @@ -16,7 +16,24 @@ impl FieldElement { v <<= 1; v ^= v_hi ^ (v_hi << 127) ^ (v_hi << 126) ^ (v_hi << 121); - v.to_le_bytes().into() + v.into() + } + + /// Inverse of [`FieldElement::mulx`]: performs division-by-x over GF(2^128). + /// + /// This is useful for implementing GHASH in terms of POLYVAL, specifically converting elements + /// of the latter back to the former. + #[inline] + #[must_use] + pub fn divx(self) -> Self { + let mut v = u128::from(self); + let v_lo = v & 1; + + v ^= v_lo ^ (v_lo << 127) ^ (v_lo << 126) ^ (v_lo << 121); + v >>= 1; + v |= v_lo << 127; + + v.into() } } @@ -52,6 +69,14 @@ mod tests { } } + /// Simple smoke test that `divx(mulx(1)) = 1`. + #[test] + fn divx_is_inverse_of_mulx() { + let one = FieldElement::from(1u128); + let x = one.mulx(); + assert_eq!(x.divx(), one); + } + /// `mulX_POLYVAL()` test vectors. /// /// These were generated by this crate when in a known-correct state,