1use 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::cm31::CM31;
10use crate::core::fields::m31::M31;
11use crate::{impl_extension_field, impl_field};
12
13pub const P4: u128 = 21267647892944572736998860269687930881; pub const R: CM31 = CM31::from_u32_unchecked(2, 1);
15
16#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
20pub struct QM31(pub CM31, pub CM31);
21pub type SecureField = QM31;
22
23pub const SECURE_EXTENSION_DEGREE: usize =
24 <SecureField as ExtensionOf<super::m31::BaseField>>::EXTENSION_DEGREE;
25
26impl_field!(QM31, P4);
27impl_extension_field!(QM31, CM31);
28
29impl QM31 {
30 pub const fn from_u32_unchecked(a: u32, b: u32, c: u32, d: u32) -> Self {
31 Self(
32 CM31::from_u32_unchecked(a, b),
33 CM31::from_u32_unchecked(c, d),
34 )
35 }
36
37 pub const fn from_m31(a: M31, b: M31, c: M31, d: M31) -> Self {
38 Self(CM31::from_m31(a, b), CM31::from_m31(c, d))
39 }
40
41 pub const fn from_m31_array(array: [M31; SECURE_EXTENSION_DEGREE]) -> Self {
42 Self::from_m31(array[0], array[1], array[2], array[3])
43 }
44
45 pub const fn to_m31_array(self) -> [M31; SECURE_EXTENSION_DEGREE] {
46 [self.0 .0, self.0 .1, self.1 .0, self.1 .1]
47 }
48
49 pub fn from_partial_evals(evals: [Self; SECURE_EXTENSION_DEGREE]) -> Self {
52 let mut res = evals[0];
53 res += evals[1] * Self::from_u32_unchecked(0, 1, 0, 0);
54 res += evals[2] * Self::from_u32_unchecked(0, 0, 1, 0);
55 res += evals[3] * Self::from_u32_unchecked(0, 0, 0, 1);
56 res
57 }
58
59 pub fn mul_cm31(self, rhs: CM31) -> Self {
62 Self(self.0 * rhs, self.1 * rhs)
63 }
64}
65
66impl Display for QM31 {
67 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68 write!(f, "({}) + ({})u", self.0, self.1)
69 }
70}
71
72impl Debug for QM31 {
73 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74 write!(f, "({}) + ({})u", self.0, self.1)
75 }
76}
77
78impl Mul for QM31 {
79 type Output = Self;
80
81 fn mul(self, rhs: Self) -> Self::Output {
82 Self(
84 self.0 * rhs.0 + R * self.1 * rhs.1,
85 self.0 * rhs.1 + self.1 * rhs.0,
86 )
87 }
88}
89
90impl From<usize> for QM31 {
91 fn from(value: usize) -> Self {
92 M31::from(value).into()
93 }
94}
95
96impl From<u32> for QM31 {
97 fn from(value: u32) -> Self {
98 M31::from(value).into()
99 }
100}
101
102impl From<i32> for QM31 {
103 fn from(value: i32) -> Self {
104 M31::from(value).into()
105 }
106}
107
108impl TryInto<M31> for QM31 {
109 type Error = ();
110
111 fn try_into(self) -> Result<M31, Self::Error> {
112 if self.1 != CM31::zero() {
113 return Err(());
114 }
115 self.0.try_into()
116 }
117}
118
119impl FieldExpOps for QM31 {
120 fn inverse(&self) -> Self {
121 assert!(!self.is_zero(), "0 has no inverse");
122 let b2 = self.1.square();
124 let ib2 = CM31(-b2.1, b2.0);
125 let denom = self.0.square() - (b2 + b2 + ib2);
126 let denom_inverse = denom.inverse();
127 Self(self.0 * denom_inverse, -self.1 * denom_inverse)
128 }
129}
130
131#[cfg(test)]
132#[macro_export]
133macro_rules! qm31 {
134 ($m0:expr, $m1:expr, $m2:expr, $m3:expr) => {{
135 use $crate::core::fields::qm31::QM31;
136 QM31::from_u32_unchecked($m0, $m1, $m2, $m3)
137 }};
138}
139
140#[cfg(test)]
141mod tests {
142 use num_traits::One;
143
144 use super::QM31;
145 use crate::core::fields::m31::P;
146 use crate::core::fields::FieldExpOps;
147 use crate::m31;
148
149 #[test]
150 fn test_inverse() {
151 let qm = qm31!(1, 2, 3, 4);
152 let qm_inv = qm.inverse();
153 assert_eq!(qm * qm_inv, QM31::one());
154 }
155
156 #[test]
157 fn test_ops() {
158 let qm0 = qm31!(1, 2, 3, 4);
159 let qm1 = qm31!(4, 5, 6, 7);
160 let m = m31!(8);
161 let qm = QM31::from(m);
162 let qm0_x_qm1 = qm31!(P - 71, 93, P - 16, 50);
163
164 assert_eq!(qm0 + qm1, qm31!(5, 7, 9, 11));
165 assert_eq!(qm1 + m, qm1 + qm);
166 assert_eq!(qm0 * qm1, qm0_x_qm1);
167 assert_eq!(qm1 * m, qm1 * qm);
168 assert_eq!(-qm0, qm31!(P - 1, P - 2, P - 3, P - 4));
169 assert_eq!(qm0 - qm1, qm31!(P - 3, P - 3, P - 3, P - 3));
170 assert_eq!(qm1 - m, qm1 - qm);
171 assert_eq!(qm0_x_qm1 / qm1, qm31!(1, 2, 3, 4));
172 assert_eq!(qm1 / m, qm1 / qm);
173 }
174}