use core::fmt::{Debug, Display};
use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};
use serde::{Deserialize, Serialize};
use super::{ComplexConjugate, FieldExpOps};
use crate::core::fields::cm31::CM31;
use crate::core::fields::m31::M31;
use crate::{impl_extension_field, impl_field};
pub const P4: u128 = 21267647892944572736998860269687930881; pub const R: CM31 = CM31::from_u32_unchecked(2, 1);
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct QM31(pub CM31, pub CM31);
pub type SecureField = QM31;
pub const SECURE_EXTENSION_DEGREE: usize =
<SecureField as ExtensionOf<super::m31::BaseField>>::EXTENSION_DEGREE;
impl_field!(QM31, P4);
impl_extension_field!(QM31, CM31);
impl QM31 {
pub const fn from_u32_unchecked(a: u32, b: u32, c: u32, d: u32) -> Self {
Self(
CM31::from_u32_unchecked(a, b),
CM31::from_u32_unchecked(c, d),
)
}
pub const fn from_m31(a: M31, b: M31, c: M31, d: M31) -> Self {
Self(CM31::from_m31(a, b), CM31::from_m31(c, d))
}
pub const fn from_m31_array(array: [M31; SECURE_EXTENSION_DEGREE]) -> Self {
Self::from_m31(array[0], array[1], array[2], array[3])
}
pub const fn to_m31_array(self) -> [M31; SECURE_EXTENSION_DEGREE] {
[self.0 .0, self.0 .1, self.1 .0, self.1 .1]
}
pub fn from_partial_evals(evals: [Self; SECURE_EXTENSION_DEGREE]) -> Self {
let mut res = evals[0];
res += evals[1] * Self::from_u32_unchecked(0, 1, 0, 0);
res += evals[2] * Self::from_u32_unchecked(0, 0, 1, 0);
res += evals[3] * Self::from_u32_unchecked(0, 0, 0, 1);
res
}
pub fn mul_cm31(self, rhs: CM31) -> Self {
Self(self.0 * rhs, self.1 * rhs)
}
}
impl Display for QM31 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "({}) + ({})u", self.0, self.1)
}
}
impl Debug for QM31 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "({}) + ({})u", self.0, self.1)
}
}
impl Mul for QM31 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(
self.0 * rhs.0 + R * self.1 * rhs.1,
self.0 * rhs.1 + self.1 * rhs.0,
)
}
}
impl From<usize> for QM31 {
fn from(value: usize) -> Self {
M31::from(value).into()
}
}
impl From<u32> for QM31 {
fn from(value: u32) -> Self {
M31::from(value).into()
}
}
impl From<i32> for QM31 {
fn from(value: i32) -> Self {
M31::from(value).into()
}
}
impl TryInto<M31> for QM31 {
type Error = ();
fn try_into(self) -> Result<M31, Self::Error> {
if self.1 != CM31::zero() {
return Err(());
}
self.0.try_into()
}
}
impl FieldExpOps for QM31 {
fn inverse(&self) -> Self {
assert!(!self.is_zero(), "0 has no inverse");
let b2 = self.1.square();
let ib2 = CM31(-b2.1, b2.0);
let denom = self.0.square() - (b2 + b2 + ib2);
let denom_inverse = denom.inverse();
Self(self.0 * denom_inverse, -self.1 * denom_inverse)
}
}
#[cfg(test)]
#[macro_export]
macro_rules! qm31 {
($m0:expr, $m1:expr, $m2:expr, $m3:expr) => {{
use $crate::core::fields::qm31::QM31;
QM31::from_u32_unchecked($m0, $m1, $m2, $m3)
}};
}
#[cfg(test)]
mod tests {
use num_traits::One;
use super::QM31;
use crate::core::fields::m31::P;
use crate::core::fields::FieldExpOps;
use crate::m31;
#[test]
fn test_inverse() {
let qm = qm31!(1, 2, 3, 4);
let qm_inv = qm.inverse();
assert_eq!(qm * qm_inv, QM31::one());
}
#[test]
fn test_ops() {
let qm0 = qm31!(1, 2, 3, 4);
let qm1 = qm31!(4, 5, 6, 7);
let m = m31!(8);
let qm = QM31::from(m);
let qm0_x_qm1 = qm31!(P - 71, 93, P - 16, 50);
assert_eq!(qm0 + qm1, qm31!(5, 7, 9, 11));
assert_eq!(qm1 + m, qm1 + qm);
assert_eq!(qm0 * qm1, qm0_x_qm1);
assert_eq!(qm1 * m, qm1 * qm);
assert_eq!(-qm0, qm31!(P - 1, P - 2, P - 3, P - 4));
assert_eq!(qm0 - qm1, qm31!(P - 3, P - 3, P - 3, P - 3));
assert_eq!(qm1 - m, qm1 - qm);
assert_eq!(qm0_x_qm1 / qm1, qm31!(1, 2, 3, 4));
assert_eq!(qm1 / m, qm1 / qm);
}
}