p3-binary-field 0.9.0-rc.2

Characteristic-2 tower fields GF(2) ⊂ GF(4) ⊂ … ⊂ GF(2^128) for Plonky3
//! The NEON backend on little-endian AArch64.
//!
//! The bit-matrix squaring needs only `neon`.
//!
//! Everything built on `PMULL` lives under the `aes` target feature.

#[cfg(target_feature = "aes")]
use core::arch::aarch64::vmull_p64;

#[cfg(target_feature = "aes")]
mod ghash;
#[cfg(target_feature = "aes")]
mod lanes;
mod square;

#[cfg(target_feature = "aes")]
pub(crate) use ghash::{
    SplitMultiplier, poly_add_128, poly_dot_128, poly_mul_128, poly_mul_128_by_64, poly_square_128,
};
pub(crate) use square::square_times;

// Every transmute between a `u128` and a vector relies on its halves being the lanes.
//
// On big-endian AArch64 they run in opposite orders.
//
// The gates that select this module name `target_endian = "little"`, and this holds them to it.
const _: () = assert!(
    cfg!(target_endian = "little"),
    "the halves of a `u128` are its vector lanes only on little-endian targets"
);

/// The carryless product of two 64-bit polynomials over `GF(2)`.
///
/// `PMULL` accumulates `b << i` for every set bit `i` of `a`.
///
/// Bit `j` of the result is therefore the coefficient of `x^j`.
#[cfg(target_feature = "aes")]
#[inline]
pub(super) fn clmul_64x64(a: u64, b: u64) -> u128 {
    // SAFETY: this function is compiled only when `target_feature = "aes"` is enabled.
    //
    // `aes` implies `neon`, and together they are what the carryless multiply requires.
    unsafe { vmull_p64(a, b) }
}