1use alloc::format;
6use alloc::string::ToString;
7use alloc::vec::Vec;
8use core::array;
9use core::fmt::{self, Display, Formatter};
10use core::iter::{Product, Sum};
11use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
12
13use itertools::Itertools;
14use num_bigint::BigUint;
15use p3_util::{as_base_slice, as_base_slice_mut, reconstitute_from_base};
16
17use super::packed_cubic_extension::PackedCubicTrinomialExtensionField;
18use super::{ExtField, HasFrobenius, HasTwoAdicCubicExtension};
19use crate::extension::{CubicTrinomial, CubicTrinomialExtendable, ExtensionAlgebra};
20use crate::field::Field;
21use crate::{
22 Algebra, ExtensionField, PackedFieldExtension, PrimeCharacteristicRing, RawDataSerializable,
23 TwoAdicField, field_to_array,
24};
25
26pub type CubicTrinomialExtensionField<F, A = F> = ExtField<F, 3, CubicTrinomial, A>;
32
33impl<F: Copy> CubicTrinomialExtensionField<F, F> {
34 #[inline]
41 pub const fn new_array<const N: usize>(input: [[F; 3]; N]) -> [Self; N] {
42 const { assert!(N > 0) }
43 let mut output = [Self::new(input[0]); N];
44 let mut i = 1;
45 while i < N {
46 output[i] = Self::new(input[i]);
47 i += 1;
48 }
49 output
50 }
51}
52
53impl<F: CubicTrinomialExtendable> ExtensionField<F> for CubicTrinomialExtensionField<F>
54where
55 PackedCubicTrinomialExtensionField<F, F::Packing>: PackedFieldExtension<F, Self>,
56{
57 type ExtensionPacking = PackedCubicTrinomialExtensionField<F, F::Packing>;
58
59 #[inline]
60 fn is_in_basefield(&self) -> bool {
61 self.value[1..].iter().all(F::is_zero)
62 }
63
64 #[inline]
65 fn as_base(&self) -> Option<F> {
66 <Self as ExtensionField<F>>::is_in_basefield(self).then(|| self.value[0])
67 }
68}
69
70impl<F: CubicTrinomialExtendable> HasFrobenius<F> for CubicTrinomialExtensionField<F> {
71 #[inline]
73 fn frobenius(&self) -> Self {
74 let a = &self.value;
75 let m = F::FROBENIUS_MATRIX;
76 let c0 = a[0] + F::dot_product::<2>(&[a[1], a[2]], &[m[0][1], m[0][2]]);
77 let c1 = F::dot_product::<2>(&[a[1], a[2]], &[m[1][1], m[1][2]]);
78 let c2 = F::dot_product::<2>(&[a[1], a[2]], &[m[2][1], m[2][2]]);
79 Self::new([c0, c1, c2])
80 }
81
82 #[inline]
84 fn repeated_frobenius(&self, count: usize) -> Self {
85 match count % 3 {
86 0 => *self,
87 _ => {
88 let mut result = *self;
89 for _ in 0..(count % 3) {
90 result = result.frobenius();
91 }
92 result
93 }
94 }
95 }
96
97 #[inline]
105 fn pseudo_inv(&self) -> Self {
106 if self.is_zero() {
107 return Self::ZERO;
108 }
109 let a_exp_p = self.frobenius();
110 let prod_conj = (*self * a_exp_p).frobenius();
111 let norm = self.compute_norm_with_prod_conj(&prod_conj);
112 debug_assert_eq!(Self::from(norm), *self * prod_conj);
113 prod_conj * norm.inverse()
114 }
115}
116
117impl<F: CubicTrinomialExtendable> CubicTrinomialExtensionField<F> {
118 #[inline]
123 fn compute_norm_with_prod_conj(&self, prod_conj: &Self) -> F {
124 let a = &self.value;
125 let b = &prod_conj.value;
126
127 let c0 = a[0] * b[0];
129 let c3 = F::dot_product::<2>(&[a[1], a[2]], &[b[2], b[1]]);
130
131 c0 + c3
132 }
133}
134
135impl<F, A> PrimeCharacteristicRing for CubicTrinomialExtensionField<F, A>
136where
137 F: CubicTrinomialExtendable,
138 A: ExtensionAlgebra<F, 3, CubicTrinomial> + Copy,
139{
140 type PrimeSubfield = <A as PrimeCharacteristicRing>::PrimeSubfield;
141
142 const ZERO: Self = Self::new([A::ZERO; 3]);
143 const ONE: Self = Self::new(field_to_array(A::ONE));
144 const TWO: Self = Self::new(field_to_array(A::TWO));
145 const NEG_ONE: Self = Self::new(field_to_array(A::NEG_ONE));
146
147 #[inline]
148 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
149 <A as PrimeCharacteristicRing>::from_prime_subfield(f).into()
150 }
151
152 #[inline]
153 fn halve(&self) -> Self {
154 Self::new(array::from_fn(|i| self.value[i].halve()))
155 }
156
157 #[inline(always)]
158 fn square(&self) -> Self {
159 let mut res = Self::default();
160 <A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_square(&self.value, &mut res.value);
161 res
162 }
163
164 #[inline]
165 fn mul_2exp_u64(&self, exp: u64) -> Self {
166 Self::new(array::from_fn(|i| self.value[i].mul_2exp_u64(exp)))
167 }
168
169 #[inline]
170 fn div_2exp_u64(&self, exp: u64) -> Self {
171 Self::new(array::from_fn(|i| self.value[i].div_2exp_u64(exp)))
172 }
173
174 #[inline]
175 fn zero_vec(len: usize) -> Vec<Self> {
176 unsafe { reconstitute_from_base(A::zero_vec(len * 3)) }
177 }
178}
179
180impl<F: CubicTrinomialExtendable> Algebra<F> for CubicTrinomialExtensionField<F> {}
181
182impl<F: CubicTrinomialExtendable> RawDataSerializable for CubicTrinomialExtensionField<F> {
183 const NUM_BYTES: usize = F::NUM_BYTES * 3;
184
185 #[inline]
186 fn into_bytes(self) -> impl IntoIterator<Item = u8> {
187 self.value.into_iter().flat_map(|x| x.into_bytes())
188 }
189
190 #[inline]
191 fn into_byte_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u8> {
192 F::into_byte_stream(input.into_iter().flat_map(|x| x.value))
193 }
194
195 #[inline]
196 fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
197 F::into_u32_stream(input.into_iter().flat_map(|x| x.value))
198 }
199
200 #[inline]
201 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
202 F::into_u64_stream(input.into_iter().flat_map(|x| x.value))
203 }
204
205 #[inline]
206 fn into_parallel_byte_streams<const N: usize>(
207 input: impl IntoIterator<Item = [Self; N]>,
208 ) -> impl IntoIterator<Item = [u8; N]> {
209 F::into_parallel_byte_streams(
210 input
211 .into_iter()
212 .flat_map(|x| (0..3).map(move |i| array::from_fn(|j| x[j].value[i]))),
213 )
214 }
215
216 #[inline]
217 fn into_parallel_u32_streams<const N: usize>(
218 input: impl IntoIterator<Item = [Self; N]>,
219 ) -> impl IntoIterator<Item = [u32; N]> {
220 F::into_parallel_u32_streams(
221 input
222 .into_iter()
223 .flat_map(|x| (0..3).map(move |i| array::from_fn(|j| x[j].value[i]))),
224 )
225 }
226
227 #[inline]
228 fn into_parallel_u64_streams<const N: usize>(
229 input: impl IntoIterator<Item = [Self; N]>,
230 ) -> impl IntoIterator<Item = [u64; N]> {
231 F::into_parallel_u64_streams(
232 input
233 .into_iter()
234 .flat_map(|x| (0..3).map(move |i| array::from_fn(|j| x[j].value[i]))),
235 )
236 }
237}
238
239impl<F: CubicTrinomialExtendable> crate::AlgebraIdentity<F> for CubicTrinomialExtensionField<F> {
240 fn algebra_id() -> Vec<u8> {
241 b"p3-power-basis-v1:X^3-X-1".to_vec()
242 }
243}
244
245impl<F: CubicTrinomialExtendable> Field for CubicTrinomialExtensionField<F> {
246 type Packing = Self;
247
248 const GENERATOR: Self = Self::new(F::EXT_GENERATOR);
249
250 fn try_inverse(&self) -> Option<Self> {
251 if self.is_zero() {
252 return None;
253 }
254 Some(self.pseudo_inv())
255 }
256
257 #[inline]
258 fn add_slices(slice_1: &mut [Self], slice_2: &[Self]) {
259 unsafe {
260 let base_slice_1 = as_base_slice_mut(slice_1);
261 let base_slice_2 = as_base_slice(slice_2);
262 F::add_slices(base_slice_1, base_slice_2);
263 }
264 }
265
266 #[inline]
267 fn order() -> BigUint {
268 F::order().pow(3)
269 }
270}
271
272impl<F: CubicTrinomialExtendable> Display for CubicTrinomialExtensionField<F> {
273 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
274 if self.is_zero() {
275 write!(f, "0")
276 } else {
277 let str = self
278 .value
279 .iter()
280 .enumerate()
281 .filter(|(_, x)| !x.is_zero())
282 .map(|(i, x)| match (i, x.is_one()) {
283 (0, _) => format!("{x}"),
284 (1, true) => "X".to_string(),
285 (1, false) => format!("{x} X"),
286 (_, true) => format!("X^{i}"),
287 (_, false) => format!("{x} X^{i}"),
288 })
289 .join(" + ");
290 write!(f, "{str}")
291 }
292 }
293}
294
295impl<F, A> Neg for CubicTrinomialExtensionField<F, A>
296where
297 F: CubicTrinomialExtendable,
298 A: Algebra<F>,
299{
300 type Output = Self;
301
302 #[inline]
303 fn neg(self) -> Self {
304 Self::new(self.value.map(A::neg))
305 }
306}
307
308impl<F, A> Add for CubicTrinomialExtensionField<F, A>
309where
310 F: CubicTrinomialExtendable,
311 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
312{
313 type Output = Self;
314
315 #[inline]
316 fn add(self, rhs: Self) -> Self {
317 Self::new(<A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_add(
318 &self.value,
319 &rhs.value,
320 ))
321 }
322}
323
324impl<F, A> Add<A> for CubicTrinomialExtensionField<F, A>
325where
326 F: CubicTrinomialExtendable,
327 A: Algebra<F>,
328{
329 type Output = Self;
330
331 #[inline]
332 fn add(mut self, rhs: A) -> Self {
333 self.value[0] += rhs;
334 self
335 }
336}
337
338impl<F, A> AddAssign for CubicTrinomialExtensionField<F, A>
339where
340 F: CubicTrinomialExtendable,
341 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
342{
343 #[inline]
344 fn add_assign(&mut self, rhs: Self) {
345 self.value =
346 <A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_add(&self.value, &rhs.value);
347 }
348}
349
350impl<F, A> AddAssign<A> for CubicTrinomialExtensionField<F, A>
351where
352 F: CubicTrinomialExtendable,
353 A: Algebra<F>,
354{
355 #[inline]
356 fn add_assign(&mut self, rhs: A) {
357 self.value[0] += rhs;
358 }
359}
360
361impl<F, A> Sum for CubicTrinomialExtensionField<F, A>
362where
363 F: CubicTrinomialExtendable,
364 A: ExtensionAlgebra<F, 3, CubicTrinomial> + Copy,
365{
366 #[inline]
367 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
368 iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
369 }
370}
371
372impl<F, A> Sub for CubicTrinomialExtensionField<F, A>
373where
374 F: CubicTrinomialExtendable,
375 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
376{
377 type Output = Self;
378
379 #[inline]
380 fn sub(self, rhs: Self) -> Self {
381 Self::new(<A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_sub(
382 &self.value,
383 &rhs.value,
384 ))
385 }
386}
387
388impl<F, A> Sub<A> for CubicTrinomialExtensionField<F, A>
389where
390 F: CubicTrinomialExtendable,
391 A: Algebra<F>,
392{
393 type Output = Self;
394
395 #[inline]
396 fn sub(self, rhs: A) -> Self {
397 let mut res = self.value;
398 res[0] -= rhs;
399 Self::new(res)
400 }
401}
402
403impl<F, A> SubAssign for CubicTrinomialExtensionField<F, A>
404where
405 F: CubicTrinomialExtendable,
406 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
407{
408 #[inline]
409 fn sub_assign(&mut self, rhs: Self) {
410 self.value =
411 <A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_sub(&self.value, &rhs.value);
412 }
413}
414
415impl<F, A> SubAssign<A> for CubicTrinomialExtensionField<F, A>
416where
417 F: CubicTrinomialExtendable,
418 A: Algebra<F>,
419{
420 #[inline]
421 fn sub_assign(&mut self, rhs: A) {
422 self.value[0] -= rhs;
423 }
424}
425
426impl<F, A> Mul for CubicTrinomialExtensionField<F, A>
427where
428 F: CubicTrinomialExtendable,
429 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
430{
431 type Output = Self;
432
433 #[inline]
434 fn mul(self, rhs: Self) -> Self {
435 let mut res = Self::default();
436 <A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_mul(
437 &self.value,
438 &rhs.value,
439 &mut res.value,
440 );
441 res
442 }
443}
444
445impl<F, A> Mul<A> for CubicTrinomialExtensionField<F, A>
446where
447 F: CubicTrinomialExtendable,
448 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
449{
450 type Output = Self;
451
452 #[inline]
453 fn mul(self, rhs: A) -> Self {
454 Self::new(<A as ExtensionAlgebra<F, 3, CubicTrinomial>>::ext_base_mul(
455 self.value, rhs,
456 ))
457 }
458}
459
460impl<F, A> MulAssign for CubicTrinomialExtensionField<F, A>
461where
462 F: CubicTrinomialExtendable,
463 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
464{
465 #[inline]
466 fn mul_assign(&mut self, rhs: Self) {
467 *self = self.clone() * rhs;
468 }
469}
470
471impl<F, A> MulAssign<A> for CubicTrinomialExtensionField<F, A>
472where
473 F: CubicTrinomialExtendable,
474 A: ExtensionAlgebra<F, 3, CubicTrinomial>,
475{
476 #[inline]
477 fn mul_assign(&mut self, rhs: A) {
478 *self = self.clone() * rhs;
479 }
480}
481
482impl<F, A> Product for CubicTrinomialExtensionField<F, A>
483where
484 F: CubicTrinomialExtendable,
485 A: ExtensionAlgebra<F, 3, CubicTrinomial> + Copy,
486{
487 #[inline]
488 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
489 iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
490 }
491}
492
493impl<F> Div for CubicTrinomialExtensionField<F>
494where
495 F: CubicTrinomialExtendable,
496{
497 type Output = Self;
498
499 #[allow(clippy::suspicious_arithmetic_impl)]
500 #[inline]
501 fn div(self, rhs: Self) -> Self::Output {
502 self * rhs.inverse()
503 }
504}
505
506impl<F> DivAssign for CubicTrinomialExtensionField<F>
507where
508 F: CubicTrinomialExtendable,
509{
510 #[inline]
511 fn div_assign(&mut self, rhs: Self) {
512 *self = *self / rhs;
513 }
514}
515
516impl<F: CubicTrinomialExtendable + HasTwoAdicCubicExtension> TwoAdicField
517 for CubicTrinomialExtensionField<F>
518{
519 const TWO_ADICITY: usize = F::EXT_TWO_ADICITY;
520
521 #[inline]
522 fn two_adic_generator(bits: usize) -> Self {
523 Self::new(F::ext_two_adic_generator(bits))
524 }
525}
526
527#[inline]
529pub fn trinomial_cubic_mul<R: PrimeCharacteristicRing>(a: &[R; 3], b: &[R; 3], res: &mut [R; 3]) {
530 let b0_plus_b2 = b[0].dup() + b[2].dup();
531 let b1_plus_b2 = b[1].dup() + b[2].dup();
532
533 res[0] = R::dot_product::<3>(a, &[b[0].dup(), b[2].dup(), b[1].dup()]);
534 res[1] = R::dot_product::<3>(a, &[b[1].dup(), b0_plus_b2.dup(), b1_plus_b2]);
535 res[2] = R::dot_product::<3>(a, &[b[2].dup(), b[1].dup(), b0_plus_b2]);
536}
537
538#[inline]
539pub fn cubic_square<R: PrimeCharacteristicRing>(a: &[R; 3], res: &mut [R; 3]) {
540 let a0_2 = a[0].double();
541 let a1_2 = a[1].double();
542 let two_a0_plus_a2 = a0_2.dup() + a[2].dup();
543 let two_a1_plus_a2 = a1_2.dup() + a[2].dup();
544
545 res[0] = R::dot_product::<2>(&[a[0].dup(), a1_2], &[a[0].dup(), a[2].dup()]);
546 res[1] = R::dot_product::<2>(&[a0_2, a[2].dup()], &[a[1].dup(), two_a1_plus_a2]);
547 res[2] = R::dot_product::<2>(&[a[1].dup(), a[2].dup()], &[a[1].dup(), two_a0_plus_a2]);
548}