use crate::tower::TowerLevel;
use crate::{BinaryField128, clmul};
pub const HAS_HARDWARE_CLMUL: bool = clmul::HAS_HARDWARE_CLMUL;
#[must_use]
#[inline]
pub fn from_tower(x: BinaryField128) -> u128 {
clmul::tower_to_poly_128(x.to_repr())
}
#[inline]
pub fn to_tower(v: u128) -> BinaryField128 {
BinaryField128::from_repr(clmul::poly_to_tower_128(v))
}
#[must_use]
#[inline]
pub fn mul(a: u128, b: u128) -> u128 {
clmul::poly_mul_128(a, b)
}
#[must_use]
#[inline]
pub fn square(a: u128) -> u128 {
clmul::poly_square_128(a)
}
#[cfg(test)]
mod tests {
use p3_field::PrimeCharacteristicRing;
use proptest::prelude::*;
use super::{from_tower, mul, square, to_tower};
use crate::BinaryField128;
fn element(bits: u128) -> BinaryField128 {
BinaryField128::from_le_bytes(bits.to_le_bytes())
}
proptest! {
#[test]
fn the_change_of_basis_round_trips(bits in any::<u128>()) {
let x = element(bits);
prop_assert_eq!(to_tower(from_tower(x)), x);
}
#[test]
fn the_change_of_basis_is_additive(a in any::<u128>(), b in any::<u128>()) {
let (x, y) = (element(a), element(b));
prop_assert_eq!(from_tower(x + y), from_tower(x) ^ from_tower(y));
}
#[test]
fn the_product_agrees_with_the_tower_product(a in any::<u128>(), b in any::<u128>()) {
let (x, y) = (element(a), element(b));
prop_assert_eq!(to_tower(mul(from_tower(x), from_tower(y))), x * y);
}
#[test]
fn the_square_agrees_with_the_tower_square(a in any::<u128>()) {
let x = element(a);
prop_assert_eq!(to_tower(square(from_tower(x))), x.square());
}
}
#[test]
fn the_change_of_basis_fixes_the_constants() {
assert_eq!(from_tower(BinaryField128::ZERO), 0);
assert_eq!(from_tower(BinaryField128::ONE), 1);
assert_eq!(to_tower(0), BinaryField128::ZERO);
assert_eq!(to_tower(1), BinaryField128::ONE);
}
}