stwo_gpu/core/fields/
cm31.rs1use core::fmt::{Debug, Display};
2use core::ops::{
3 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
4};
5
6use serde::{Deserialize, Serialize};
7
8use super::{ComplexConjugate, FieldExpOps};
9use crate::core::fields::m31::M31;
10use crate::{impl_extension_field, impl_field};
11pub const P2: u64 = 4611686014132420609; #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
17pub struct CM31(pub M31, pub M31);
18
19impl_field!(CM31, P2);
20impl_extension_field!(CM31, M31);
21
22impl CM31 {
23 pub const fn from_u32_unchecked(a: u32, b: u32) -> CM31 {
24 Self(M31::from_u32_unchecked(a), M31::from_u32_unchecked(b))
25 }
26
27 pub const fn from_m31(a: M31, b: M31) -> CM31 {
28 Self(a, b)
29 }
30}
31
32impl Display for CM31 {
33 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34 write!(f, "{} + {}i", self.0, self.1)
35 }
36}
37
38impl Debug for CM31 {
39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 write!(f, "{} + {}i", self.0, self.1)
41 }
42}
43
44impl Mul for CM31 {
45 type Output = Self;
46
47 fn mul(self, rhs: Self) -> Self::Output {
48 Self(
50 self.0 * rhs.0 - self.1 * rhs.1,
51 self.0 * rhs.1 + self.1 * rhs.0,
52 )
53 }
54}
55
56impl TryInto<M31> for CM31 {
57 type Error = ();
58
59 fn try_into(self) -> Result<M31, Self::Error> {
60 if self.1 != M31::zero() {
61 return Err(());
62 }
63 Ok(self.0)
64 }
65}
66
67impl FieldExpOps for CM31 {
68 fn inverse(&self) -> Self {
69 assert!(!self.is_zero(), "0 has no inverse");
70 Self(self.0, -self.1) * (self.0.square() + self.1.square()).inverse()
72 }
73}
74
75#[cfg(test)]
76#[macro_export]
77macro_rules! cm31 {
78 ($m0:expr, $m1:expr) => {
79 CM31::from_u32_unchecked($m0, $m1)
80 };
81}
82
83#[cfg(test)]
84mod tests {
85 use super::CM31;
86 use crate::core::fields::m31::P;
87 use crate::core::fields::FieldExpOps;
88 use crate::m31;
89
90 #[test]
91 fn test_inverse() {
92 let cm = cm31!(1, 2);
93 let cm_inv = cm.inverse();
94 assert_eq!(cm * cm_inv, cm31!(1, 0));
95 }
96
97 #[test]
98 fn test_ops() {
99 let cm0 = cm31!(1, 2);
100 let cm1 = cm31!(4, 5);
101 let m = m31!(8);
102 let cm = CM31::from(m);
103 let cm0_x_cm1 = cm31!(P - 6, 13);
104
105 assert_eq!(cm0 + cm1, cm31!(5, 7));
106 assert_eq!(cm1 + m, cm1 + cm);
107 assert_eq!(cm0 * cm1, cm0_x_cm1);
108 assert_eq!(cm1 * m, cm1 * cm);
109 assert_eq!(-cm0, cm31!(P - 1, P - 2));
110 assert_eq!(cm0 - cm1, cm31!(P - 3, P - 3));
111 assert_eq!(cm1 - m, cm1 - cm);
112 assert_eq!(cm0_x_cm1 / cm1, cm31!(1, 2));
113 assert_eq!(cm1 / m, cm1 / cm);
114 }
115}