use core::ops::{Add, Mul, Sub};
use p3_field::op_assign_macros::{impl_add_base_field, impl_sub_base_field};
use p3_field::{Algebra, HasSubfield};
use crate::tower::TowerLevel;
use crate::{BinaryField2, BinaryField128};
const LOW_BITS: u128 = 0x5555_5555_5555_5555_5555_5555_5555_5555;
const HIGH_BITS: u128 = !LOW_BITS;
#[inline]
const fn mul_x0(bits: u128) -> u128 {
let b1 = bits & HIGH_BITS;
(b1 >> 1) ^ ((bits & LOW_BITS) << 1) ^ b1
}
impl From<BinaryField2> for BinaryField128 {
#[inline]
fn from(x: BinaryField2) -> Self {
Self::from_repr(u128::from(x.to_repr()))
}
}
impl_add_base_field!(BinaryField128, BinaryField2);
impl_sub_base_field!(BinaryField128, BinaryField2);
impl Mul<BinaryField2> for BinaryField128 {
type Output = Self;
#[inline]
fn mul(self, rhs: BinaryField2) -> Self {
let bits = self.to_repr();
let c = rhs.to_repr();
let c0 = u128::from(c & 1).wrapping_neg();
let c1 = u128::from((c >> 1) & 1).wrapping_neg();
Self::from_repr((c0 & bits) ^ (c1 & mul_x0(bits)))
}
}
impl Mul<BinaryField128> for BinaryField2 {
type Output = BinaryField128;
#[inline]
fn mul(self, rhs: BinaryField128) -> BinaryField128 {
rhs * self
}
}
impl Algebra<BinaryField2> for BinaryField128 {}
impl HasSubfield<BinaryField2> for BinaryField128 {
#[inline]
fn as_subfield(&self) -> Option<BinaryField2> {
let bits = self.to_repr();
(bits & !3 == 0).then(|| BinaryField2::from_repr(bits as u8))
}
#[inline]
fn all_in_subfield(values: &[Self]) -> bool {
values.iter().fold(0, |acc, v| acc | v.to_repr()) & !3 == 0
}
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use p3_field::{HasSubfield, PrimeCharacteristicRing};
use p3_field_testing::test_has_subfield;
use proptest::prelude::*;
use crate::tower::TowerLevel;
use crate::{BinaryField2, BinaryField8, BinaryField128};
fn gf4() -> impl Iterator<Item = BinaryField2> {
(0..4).map(BinaryField2::from_repr)
}
#[test]
fn the_embedding_is_a_ring_homomorphism_on_every_pair() {
assert_eq!(
BinaryField128::from(BinaryField2::ZERO),
BinaryField128::ZERO
);
assert_eq!(BinaryField128::from(BinaryField2::ONE), BinaryField128::ONE);
for a in gf4() {
for b in gf4() {
let (x, y) = (BinaryField128::from(a), BinaryField128::from(b));
assert_eq!(BinaryField128::from(a + b), x + y, "{a} + {b}");
assert_eq!(BinaryField128::from(a * b), x * y, "{a} * {b}");
assert_eq!(BinaryField128::from(a * b), x.reference_mul(y), "{a} * {b}");
}
}
}
#[test]
fn the_embedding_factors_through_the_byte_level() {
let byte = |a: BinaryField2| BinaryField8::from_repr(a.to_repr());
for a in gf4() {
assert_eq!(BinaryField128::from(a), BinaryField128::from(byte(a)));
for b in gf4() {
assert_eq!(byte(a * b), byte(a) * byte(b), "{a} * {b}");
}
}
}
#[test]
fn every_subfield_element_narrows_back_to_itself() {
for a in gf4() {
assert_eq!(BinaryField128::from(a).as_subfield(), Some(a));
}
}
#[test]
fn the_has_subfield_contract_holds() {
test_has_subfield::<BinaryField128, BinaryField2>();
}
#[test]
fn every_bit_above_the_lowest_two_lies_outside_the_subfield() {
let members: Vec<BinaryField128> = gf4().map(BinaryField128::from).collect();
for s in 0..4u128 {
for k in 2..128 {
let x = BinaryField128::from_repr(s | (1u128 << k));
assert_eq!(x.as_subfield(), None, "{s} with bit {k} set");
let mut values = members.clone();
values.insert(k % (members.len() + 1), x);
assert!(
!BinaryField128::all_in_subfield(&values),
"{s} with bit {k} set among the subfield elements"
);
}
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(1000))]
#[test]
fn the_masked_product_agrees_with_the_tower_product(bits: u128) {
let x = BinaryField128::from_repr(bits);
for s in gf4() {
let image = BinaryField128::from(s);
prop_assert_eq!(x * s, x * image, "scalar {}", s);
prop_assert_eq!(s * x, image * x, "scalar {}", s);
}
}
#[test]
fn narrowing_accepts_exactly_the_low_two_bits(bits: u128, shift in 0u32..128) {
let bits = bits >> shift;
let x = BinaryField128::from_repr(bits);
match x.as_subfield() {
Some(s) => {
prop_assert!(bits < 4);
prop_assert_eq!(BinaryField128::from(s), x);
}
None => prop_assert!(bits >= 4),
}
}
#[test]
fn all_in_subfield_agrees_with_narrowing_each_element(
bits in prop::collection::vec(
prop_oneof![
3 => 0u128..4,
1 => (any::<u128>(), 0u32..128).prop_map(|(bits, shift)| bits >> shift),
],
0..12,
),
) {
let values: Vec<BinaryField128> =
bits.into_iter().map(BinaryField128::from_repr).collect();
prop_assert_eq!(
BinaryField128::all_in_subfield(&values),
values.iter().all(|v| v.as_subfield().is_some())
);
}
}
}