1use core::iter::{Product, Sum};
2use std::{
3 cmp::Ordering,
4 fmt::Debug,
5 hash::{Hash, Hasher},
6 marker::PhantomData,
7 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8 str,
9};
10
11use derive_more::{AsMut, AsRef};
12use ff::Field;
13use hybrid_array::{Array, ArraySize, AssocArraySize};
14use itertools::{izip, Itertools};
15use itybity::{FromBitIterator, ToBits};
16use rand::RngCore;
17use serde::{Deserialize, Serialize};
18use serde_with::serde_as;
19use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
20use typenum::{Prod, Unsigned, U64, U8};
21
22use crate::{
23 algebra::{
24 field::{binary::Gf2, FieldExtension},
25 ops::{AccReduce, DefaultDotProduct, DotProduct, IntoWide, MulAccReduce, ReduceWide},
26 uniform_bytes::FromUniformBytes,
27 },
28 types::{HeapArray, Positive},
29 utils::IntoExactSizeIterator,
30};
31
32#[serde_as]
33#[derive(Clone, Copy, Debug, Eq, AsRef, AsMut, Serialize, Deserialize)]
34#[repr(transparent)]
35pub struct Gf2Ext<P: Gf2ExtParams, const LIMBS: usize> {
36 #[serde_as(as = "[_; LIMBS]")]
37 pub(crate) data: [u64; LIMBS],
38 _id: PhantomData<P>,
39}
40
41impl<P: Gf2ExtParams, const LIMBS: usize> AsRef<[u8]> for Gf2Ext<P, LIMBS> {
42 fn as_ref(&self) -> &[u8] {
43 unsafe {
48 std::slice::from_raw_parts(
49 self.data.as_ptr() as *const u8,
50 LIMBS * std::mem::size_of::<u64>(),
51 )
52 }
53 }
54}
55
56impl<P: Gf2ExtParams, const LIMBS: usize> AsMut<[u8]> for Gf2Ext<P, LIMBS> {
57 fn as_mut(&mut self) -> &mut [u8] {
58 unsafe {
63 std::slice::from_raw_parts_mut(
64 self.data.as_mut_ptr() as *mut u8,
65 LIMBS * std::mem::size_of::<u64>(),
66 )
67 }
68 }
69}
70
71impl<P: Gf2ExtParams, const LIMBS: usize> PartialEq<Self> for Gf2Ext<P, LIMBS> {
72 fn eq(&self, other: &Self) -> bool {
73 self.cmp(other) == Ordering::Equal
74 }
75}
76
77impl<P: Gf2ExtParams, const LIMBS: usize> PartialOrd<Self> for Gf2Ext<P, LIMBS> {
78 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
79 Some(self.cmp(other))
80 }
81}
82
83impl<P: Gf2ExtParams, const LIMBS: usize> Ord for Gf2Ext<P, LIMBS> {
84 fn cmp(&self, other: &Self) -> Ordering {
85 self.data.cmp(&other.data)
86 }
87}
88
89impl<P: Gf2ExtParams, const LIMBS: usize> Hash for Gf2Ext<P, LIMBS> {
90 fn hash<H: Hasher>(&self, state: &mut H) {
91 let bytes: &[u8] = self.as_ref();
92 bytes.iter().for_each(|x| {
93 x.hash(state);
94 });
95 }
96}
97
98#[derive(Clone, Copy)]
100pub struct Gf2LimbsWide<const LIMBS: usize> {
101 pub(crate) low: [u64; LIMBS],
102 pub(crate) high: [u64; LIMBS],
103}
104
105pub trait Gf2ExtParams: Copy + Debug + Eq + PartialEq + Sync + Send + Unpin + 'static {
106 type Degree: ArraySize + Positive;
108
109 type Bytes: ArraySize + Positive;
111 const POLY_MOD_ONES: &[usize];
113}
114
115impl<P: Gf2ExtParams, const LIMBS: usize> Gf2Ext<P, LIMBS> {
116 pub const fn new(data: [u64; LIMBS]) -> Self {
117 Self {
118 data,
119 _id: PhantomData,
120 }
121 }
122
123 const ZERO: Self = Self::new([0u64; LIMBS]);
124 const ONE: Self = Self::new({
125 let mut tmp = [0u64; LIMBS];
126 tmp[0] = 1;
127 tmp
128 });
129}
130
131impl<P: Gf2ExtParams, const LIMBS: usize> Gf2Ext<P, LIMBS> {
132 pub fn as_mut_ne_bytes_slice(&mut self) -> &mut [u8] {
133 bytemuck::bytes_of_mut(&mut self.data)
134 }
135
136 pub fn as_ne_bytes_slice(&self) -> &[u8] {
137 bytemuck::bytes_of(&self.data)
138 }
139
140 pub fn from_limbs(val: [u64; LIMBS]) -> Self {
141 Self::new(val)
142 }
143
144 pub fn from_u64(val: u64) -> Self {
145 let mut tmp = [0u64; LIMBS];
146 tmp[0] = val;
147 Self::from_limbs(tmp)
148 }
149
150 pub fn from_u128(val: u128) -> Self {
151 let mut tmp = [0u64; LIMBS];
152 tmp[0] = val as u64;
153 tmp[1] = (val >> 64) as u64;
154 Self::from_limbs(tmp)
155 }
156}
157
158impl<P: Gf2ExtParams, const LIMBS: usize> Default for Gf2Ext<P, LIMBS> {
159 fn default() -> Self {
160 Self::ZERO
161 }
162}
163
164impl<const LIMBS: usize> Default for Gf2LimbsWide<LIMBS> {
165 fn default() -> Self {
166 Self {
167 low: [0u64; LIMBS],
168 high: [0u64; LIMBS],
169 }
170 }
171}
172
173impl<P: Gf2ExtParams, const LIMBS: usize> From<bool> for Gf2Ext<P, LIMBS> {
176 #[inline]
177 fn from(value: bool) -> Self {
178 Self::from_u64(value as u64)
179 }
180}
181
182impl<P: Gf2ExtParams, const LIMBS: usize> From<u8> for Gf2Ext<P, LIMBS> {
183 #[inline]
184 fn from(value: u8) -> Self {
185 Self::from_u64(value as u64)
186 }
187}
188
189impl<P: Gf2ExtParams, const LIMBS: usize> From<u16> for Gf2Ext<P, LIMBS> {
190 #[inline]
191 fn from(value: u16) -> Self {
192 Self::from_u64(value as u64)
193 }
194}
195
196impl<P: Gf2ExtParams, const LIMBS: usize> From<u32> for Gf2Ext<P, LIMBS> {
197 #[inline]
198 fn from(value: u32) -> Self {
199 Self::from_u64(value as u64)
200 }
201}
202
203impl<P: Gf2ExtParams, const LIMBS: usize> From<u64> for Gf2Ext<P, LIMBS> {
204 #[inline]
205 fn from(value: u64) -> Self {
206 Self::from_u64(value)
207 }
208}
209
210impl<P: Gf2ExtParams, const LIMBS: usize> From<u128> for Gf2Ext<P, LIMBS> {
211 #[inline]
212 fn from(value: u128) -> Self {
213 Self::from_u128(value)
214 }
215}
216
217impl<P: Gf2ExtParams, const LIMBS: usize> Field for Gf2Ext<P, LIMBS>
220where
221 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
222{
223 const ZERO: Self = Self::ZERO;
224 const ONE: Self = Self::ONE;
225
226 fn random(mut rng: impl RngCore) -> Self {
227 let mut tmp = Self::default();
228 rng.fill_bytes(tmp.as_mut_ne_bytes_slice());
229 tmp
230 }
231
232 fn square(&self) -> Self {
233 self * self
234 }
235
236 fn double(&self) -> Self {
237 self + self
238 }
239
240 fn invert(&self) -> CtOption<Self> {
241 unimplemented!()
242 }
243
244 fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) {
245 unimplemented!()
246 }
247}
248
249impl<P: Gf2ExtParams, const LIMBS: usize> ConditionallySelectable for Gf2Ext<P, LIMBS> {
250 #[inline]
251 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
252 Self::from_limbs(std::array::from_fn(|k| {
253 u64::conditional_select(&a.data[k], &b.data[k], choice)
254 }))
255 }
256}
257
258impl<P: Gf2ExtParams, const LIMBS: usize> ConstantTimeEq for Gf2Ext<P, LIMBS> {
259 fn ct_eq(&self, other: &Self) -> Choice {
260 izip!(self.data, other.data).fold(1u8.into(), |r, ab| r & ab.0.ct_eq(&ab.1))
261 }
262}
263
264#[macros::op_variants(borrowed)]
269impl<P: Gf2ExtParams, const LIMBS: usize> Neg for Gf2Ext<P, LIMBS> {
270 type Output = Gf2Ext<P, LIMBS>;
271
272 #[inline]
273 fn neg(self) -> Self::Output {
274 self
275 }
276}
277
278#[macros::op_variants(owned, borrowed, flipped_commutative)]
281impl<P: Gf2ExtParams, const LIMBS: usize> Add<&Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS> {
282 type Output = Gf2Ext<P, LIMBS>;
283
284 #[inline]
285 #[allow(clippy::op_ref)]
286 fn add(mut self, rhs: &Self::Output) -> Self::Output {
287 self += rhs;
288 self
289 }
290}
291
292#[macros::op_variants(owned)]
293impl<P: Gf2ExtParams, const LIMBS: usize> AddAssign<&Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS> {
294 #[allow(clippy::suspicious_op_assign_impl)]
295 fn add_assign(&mut self, rhs: &Self) {
296 izip!(&mut self.data, rhs.data).for_each(|(a, b)| *a ^= b);
297 }
298}
299
300#[macros::op_variants(owned, borrowed, flipped)]
303impl<P: Gf2ExtParams, const LIMBS: usize> Sub<&Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS> {
304 type Output = Gf2Ext<P, LIMBS>;
305
306 #[inline]
307 #[allow(clippy::suspicious_arithmetic_impl)]
308 fn sub(self, rhs: &Self::Output) -> Self::Output {
309 self + rhs
310 }
311}
312
313#[macros::op_variants(owned)]
314impl<P: Gf2ExtParams, const LIMBS: usize> SubAssign<&Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS> {
315 #[inline]
316 #[allow(clippy::suspicious_op_assign_impl)]
317 fn sub_assign(&mut self, rhs: &Self) {
318 *self += rhs;
319 }
320}
321
322#[macros::op_variants(owned, borrowed)]
325impl<P: Gf2ExtParams, const LIMBS: usize> Mul<&Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS>
326where
327 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
328{
329 type Output = Gf2Ext<P, LIMBS>;
330
331 #[inline]
332 fn mul(mut self, rhs: &Self::Output) -> Self::Output {
333 self *= rhs;
334 self
335 }
336}
337
338impl<P: Gf2ExtParams, const LIMBS: usize> Mul<Gf2Ext<P, LIMBS>> for &Gf2Ext<P, LIMBS>
339where
340 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
341{
342 type Output = Gf2Ext<P, LIMBS>;
343
344 #[inline]
345 fn mul(self, rhs: Self::Output) -> Self::Output {
346 rhs * self
347 }
348}
349
350impl<P: Gf2ExtParams, const LIMBS: usize> MulAssign<&Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS>
351where
352 Gf2Ext<P, LIMBS>: MulAssign,
353{
354 #[inline]
355 fn mul_assign(&mut self, rhs: &Gf2Ext<P, LIMBS>) {
356 *self *= *rhs;
357 }
358}
359
360impl<P: Gf2ExtParams, const LIMBS: usize> MulAssign<Gf2> for Gf2Ext<P, LIMBS>
361where
362 Gf2Ext<P, LIMBS>: MulAssign,
363{
364 #[inline]
365 fn mul_assign(&mut self, rhs: Gf2) {
366 self.data
367 .iter_mut()
368 .for_each(|limb: &mut u64| *limb *= rhs.0 as u64)
369 }
370}
371
372impl<P: Gf2ExtParams, const LIMBS: usize> MulAssign<&Gf2> for Gf2Ext<P, LIMBS>
373where
374 Gf2Ext<P, LIMBS>: MulAssign,
375{
376 #[inline]
377 fn mul_assign(&mut self, rhs: &Gf2) {
378 self.data
379 .iter_mut()
380 .for_each(|limb: &mut u64| *limb *= rhs.0 as u64)
381 }
382}
383
384impl<P: Gf2ExtParams, const LIMBS: usize> MulAssign for Gf2Ext<P, LIMBS>
385where
386 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
387 Gf2Ext<P, LIMBS>: IntoWide<Gf2LimbsWide<LIMBS>>,
388{
389 fn mul_assign(&mut self, rhs: Self) {
390 let res_wide = self.mul_wide(rhs);
391 *self = Self::reduce_mod_order(res_wide)
392 }
393}
394
395impl<P: Gf2ExtParams, const LIMBS: usize> Sum for Gf2Ext<P, LIMBS> {
396 #[inline]
397 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
398 iter.fold(Gf2Ext::ZERO, |a, b| a + b)
399 }
400}
401
402impl<'a, P: Gf2ExtParams, const LIMBS: usize> Sum<&'a Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS> {
403 #[inline]
404 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
405 iter.fold(Gf2Ext::ZERO, |a, b| a + b)
406 }
407}
408
409impl<P: Gf2ExtParams, const LIMBS: usize> Product for Gf2Ext<P, LIMBS>
410where
411 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
412{
413 #[inline]
414 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
415 iter.fold(Gf2Ext::ONE, |a, b| a * b)
416 }
417}
418
419impl<'a, P: Gf2ExtParams, const LIMBS: usize> Product<&'a Gf2Ext<P, LIMBS>> for Gf2Ext<P, LIMBS>
420where
421 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
422{
423 #[inline]
424 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
425 iter.fold(Gf2Ext::ONE, |a, b| a * b)
426 }
427}
428
429impl<P: Gf2ExtParams, const LIMBS: usize> FieldExtension for Gf2Ext<P, LIMBS>
431where
432 Gf2Ext<P, LIMBS>: MulWide<Output = Gf2LimbsWide<LIMBS>>,
433 [u8; LIMBS]: AssocArraySize,
434 <[u8; LIMBS] as AssocArraySize>::Size: ArraySize + Positive + Mul<U8> + Mul<U64>,
435 Prod<<[u8; LIMBS] as AssocArraySize>::Size, U8>: ArraySize + Positive,
436 Prod<<[u8; LIMBS] as AssocArraySize>::Size, U64>: ArraySize + Positive,
437{
438 type Subfield = Gf2;
439
440 type Degree = P::Degree;
441 type FieldBitSize = Prod<<[u8; LIMBS] as AssocArraySize>::Size, U64>;
442 type FieldBytesSize = Prod<<[u8; LIMBS] as AssocArraySize>::Size, U8>;
443
444 fn to_subfield_elements(&self) -> impl ExactSizeIterator<Item = Self::Subfield> {
445 self.data.iter_lsb0().take(P::Degree::USIZE).map(Gf2::from)
446 }
447
448 fn from_subfield_elements(elems: &[Self::Subfield]) -> Option<Self> {
449 if elems.len() == P::Degree::to_usize() {
450 let mut iter = elems
451 .chunks_exact(64)
452 .map(|a| u64::from_lsb0_iter(a.iter().map(bool::from)));
453 Some(Self::new(std::array::from_fn(|_| iter.next().unwrap())))
454 } else {
455 None
456 }
457 }
458
459 fn to_le_bytes(&self) -> impl IntoIterator<Item = u8> {
460 (0..LIMBS)
461 .cartesian_product((0..64).step_by(8))
462 .map(|(limb, shift)| ((self.data[limb] >> shift) & 0xFF) as u8)
463 }
464
465 fn from_le_bytes(bytes: &[u8]) -> Option<Self> {
466 if bytes.len() != Self::FieldBytesSize::USIZE {
467 return None;
468 }
469
470 let mut it = bytes.chunks_exact(8).take(LIMBS);
471 Some(Self::new(std::array::from_fn(|_| {
472 u64::from_le_bytes(it.next().unwrap().try_into().unwrap())
473 })))
474 }
475
476 fn mul_by_subfield(&self, other: &Self::Subfield) -> Self {
477 *self * other
478 }
479
480 fn generator() -> Self {
481 Self::from_u64(2u64) }
483
484 fn random_elements<M: Positive>(mut rng: impl RngCore) -> HeapArray<Self, M> {
486 let mut buf = HeapArray::<Self, M>::default().into_box_bytes();
487 rng.fill_bytes(&mut buf);
488 HeapArray::from_box_bytes(buf)
489 }
490
491 fn linear_orthomorphism(&self) -> Self {
494 let mut res = Self::default();
495 for i in 0..LIMBS / 2 {
496 res.data[i] = self.data[i] ^ self.data[LIMBS - i - 1];
497 res.data[LIMBS - i - 1] = self.data[i];
498 }
499 if LIMBS % 2 == 1 {
500 let k = LIMBS / 2;
501 let (tl, th) = (self.data[k] as u32, (self.data[k] >> 32) as u32);
502
503 let (rl, rh) = (tl ^ th, tl);
504 res.data[k] = rl as u64 + ((rh as u64) << 32);
505 }
506
507 res
508 }
509}
510
511unsafe impl<P: Gf2ExtParams, const LIMBS: usize> bytemuck::Zeroable for Gf2Ext<P, LIMBS> {
512 fn zeroed() -> Self {
513 Self::ZERO
514 }
515}
516unsafe impl<P: Gf2ExtParams, const LIMBS: usize> bytemuck::Pod for Gf2Ext<P, LIMBS> {}
517
518impl<P: Gf2ExtParams, const LIMBS: usize> Add<Gf2> for Gf2Ext<P, LIMBS> {
519 type Output = Self;
520
521 #[allow(clippy::suspicious_arithmetic_impl)]
522 fn add(mut self, rhs: Gf2) -> Self::Output {
523 let m = (-(rhs.0 as i64)) as u64;
525 self.data.iter_mut().for_each(|v: &mut u64| *v ^= m);
526 self
527 }
528}
529
530impl<'a, P: Gf2ExtParams, const LIMBS: usize> Add<&'a Gf2> for Gf2Ext<P, LIMBS> {
531 type Output = Self;
532
533 #[inline]
534 fn add(self, rhs: &'a Gf2) -> Self::Output {
535 self + *rhs
536 }
537}
538
539impl<P: Gf2ExtParams, const LIMBS: usize> Mul<Gf2> for Gf2Ext<P, LIMBS> {
540 type Output = Self;
541
542 #[allow(clippy::suspicious_arithmetic_impl)]
543 fn mul(mut self, rhs: Gf2) -> Self::Output {
544 let m = (-(rhs.0 as i64)) as u64;
546 self.data.iter_mut().for_each(|v: &mut u64| *v &= m);
547 self
548 }
549}
550
551impl<'a, P: Gf2ExtParams, const LIMBS: usize> Mul<&'a Gf2> for Gf2Ext<P, LIMBS> {
552 type Output = Self;
553
554 #[inline]
555 fn mul(self, rhs: &'a Gf2) -> Self::Output {
556 self * *rhs
557 }
558}
559
560impl<const LIMBS: usize> AddAssign for Gf2LimbsWide<LIMBS> {
564 fn add_assign(&mut self, rhs: Self) {
565 izip!(&mut self.low, rhs.low).for_each(|(a, b)| *a ^= b);
566 izip!(&mut self.high, rhs.high).for_each(|(a, b)| *a ^= b);
567 }
568}
569
570impl<P: Gf2ExtParams, const LIMBS: usize> IntoWide<Gf2LimbsWide<LIMBS>> for Gf2Ext<P, LIMBS> {
572 #[inline]
573 fn to_wide(&self) -> Gf2LimbsWide<LIMBS> {
574 Gf2LimbsWide {
575 low: self.data,
576 high: [0u64; LIMBS],
577 }
578 }
579
580 #[inline]
581 fn zero_wide() -> Gf2LimbsWide<LIMBS> {
582 Default::default()
583 }
584}
585
586impl<P: Gf2ExtParams, const LIMBS: usize> ReduceWide<Gf2LimbsWide<LIMBS>> for Gf2Ext<P, LIMBS> {
587 fn reduce_mod_order(a: Gf2LimbsWide<LIMBS>) -> Self {
590 let Gf2LimbsWide { mut low, mut high } = a;
591
592 let ones = P::POLY_MOD_ONES;
593
594 macro_rules! reduce_1step {
597 ($out_low:expr, $out_high:expr, $inp:expr) => {
598 for k in ones {
599 $out_high ^= $inp >> (64 - k);
600 }
601 $out_low ^= $inp;
602 for k in ones {
603 $out_low ^= $inp << k;
604 }
605 };
606 }
607
608 reduce_1step!(low[LIMBS - 1], high[0], high[LIMBS - 1]);
609 for i in (0..LIMBS - 1).rev() {
610 reduce_1step!(low[i], low[i + 1], high[i]);
611 }
612
613 Gf2Ext {
614 data: low,
615 _id: PhantomData,
616 }
617 }
618}
619
620impl<P: Gf2ExtParams, const LIMBS: usize> MulAccReduce for Gf2Ext<P, LIMBS>
622where
623 Self: MulWide<Output = Gf2LimbsWide<LIMBS>>,
624{
625 type WideType = Gf2LimbsWide<LIMBS>;
626
627 #[inline]
628 fn mul_acc(acc: &mut Self::WideType, a: Self, b: Self) {
629 *acc += a.mul_wide(b)
630 }
631}
632
633impl<P: Gf2ExtParams, const LIMBS: usize> DefaultDotProduct for Gf2Ext<P, LIMBS> where
634 Self: MulAccReduce
635{
636}
637
638impl<'a, P: Gf2ExtParams, const LIMBS: usize> DotProduct<Self, &'a Self> for Gf2Ext<P, LIMBS>
640where
641 Self: DefaultDotProduct,
642{
643 #[inline]
644 fn dot<I1, I2>(a: I1, b: I2) -> Self
645 where
646 I1: IntoExactSizeIterator<Item = Self>,
647 I2: IntoExactSizeIterator<Item = &'a Self>,
648 {
649 Self::dot(a, b.into_iter().copied())
650 }
651}
652
653impl<'a, 'b, P: Gf2ExtParams, const LIMBS: usize> DotProduct<&'a Self, &'b Self>
655 for Gf2Ext<P, LIMBS>
656where
657 Self: DefaultDotProduct,
658{
659 #[inline]
660 fn dot<I1, I2>(a: I1, b: I2) -> Self
661 where
662 I1: IntoExactSizeIterator<Item = &'a Self>,
663 I2: IntoExactSizeIterator<Item = &'b Self>,
664 {
665 Self::dot(a.into_iter().copied(), b)
666 }
667}
668
669impl<P: Gf2ExtParams, const LIMBS: usize> IntoWide for Gf2Ext<P, LIMBS> {
670 #[inline]
671 fn to_wide(&self) -> Self {
672 *self
673 }
674
675 #[inline]
676 fn zero_wide() -> Self {
677 <Self as IntoWide>::to_wide(&Self::ZERO)
678 }
679}
680
681impl<P: Gf2ExtParams, const LIMBS: usize> ReduceWide for Gf2Ext<P, LIMBS> {
682 #[inline]
683 fn reduce_mod_order(a: Self) -> Self {
684 a
685 }
686}
687
688impl<P: Gf2ExtParams, const LIMBS: usize> MulAccReduce<Self, Gf2> for Gf2Ext<P, LIMBS> {
690 type WideType = Self;
691
692 #[inline]
693 fn mul_acc(acc: &mut Self, a: Self, b: Gf2) {
694 *acc += a * b;
695 }
696}
697
698impl<P: Gf2ExtParams, const LIMBS: usize> DefaultDotProduct<Self, Gf2> for Gf2Ext<P, LIMBS> {}
699
700impl<'a, P: Gf2ExtParams, const LIMBS: usize> MulAccReduce<&'a Self, Gf2> for Gf2Ext<P, LIMBS> {
702 type WideType = Self;
703
704 #[inline]
705 fn mul_acc(acc: &mut Self, a: &'a Self, b: Gf2) {
706 Self::mul_acc(acc, *a, b);
707 }
708}
709
710impl<P: Gf2ExtParams, const LIMBS: usize> DefaultDotProduct<&Self, Gf2> for Gf2Ext<P, LIMBS> {}
711
712impl<'a, 'b, P: Gf2ExtParams, const LIMBS: usize> MulAccReduce<&'a Self, &'b Gf2>
714 for Gf2Ext<P, LIMBS>
715{
716 type WideType = Self;
717
718 #[inline]
719 fn mul_acc(acc: &mut Self, a: &'a Self, b: &'b Gf2) {
720 Self::mul_acc(acc, a, *b);
721 }
722}
723
724impl<P: Gf2ExtParams, const LIMBS: usize> DefaultDotProduct<&Self, &Gf2> for Gf2Ext<P, LIMBS> {}
725
726impl<P: Gf2ExtParams, const LIMBS: usize> AccReduce for Gf2Ext<P, LIMBS> {
727 type WideType = Self;
728
729 fn acc(acc: &mut Self, a: Self) {
730 *acc += a;
731 }
732}
733
734impl<P: Gf2ExtParams, const LIMBS: usize> AccReduce<&Self> for Gf2Ext<P, LIMBS> {
735 type WideType = Self;
736
737 fn acc(acc: &mut Self, a: &Self) {
738 *acc += a;
739 }
740}
741
742pub trait MulWide<Rhs = Self> {
743 type Output;
744 fn mul_wide(self, rhs: Rhs) -> Self::Output;
745}
746
747impl<P: Gf2ExtParams, const LIMBS: usize> FromUniformBytes for Gf2Ext<P, LIMBS>
748where
749 [u8; LIMBS]: AssocArraySize,
750 <[u8; LIMBS] as AssocArraySize>::Size: ArraySize + Positive + Mul<U8> + Mul<U64>,
751 Prod<<[u8; LIMBS] as AssocArraySize>::Size, U8>: ArraySize + Positive,
752{
753 type UniformBytes = Prod<<[u8; LIMBS] as AssocArraySize>::Size, U8>;
754
755 fn from_uniform_bytes(a: &Array<u8, Self::UniformBytes>) -> Self {
756 let mut it = a.chunks_exact(8).take(LIMBS);
757 Self::new(std::array::from_fn(|_| {
758 u64::from_le_bytes(it.next().unwrap().try_into().unwrap())
759 }))
760 }
761}
762
763macro_rules! impl_wide_mul {
765 ($params:ty, 1) => {
766 impl $crate::algebra::field::binary::gf2_ext::MulWide for Gf2Ext<$params, 1> {
767 type Output = Gf2LimbsWide<1>;
768 fn mul_wide(self, rhs: Self) -> Self::Output {
769 let (low, high) =
770 $crate::algebra::ops::clmul::carry_less_mul_1limb(self.data, rhs.data);
771 Gf2LimbsWide { low, high }
772 }
773 }
774 };
775 ($params:ty, 2) => {
776 impl $crate::algebra::field::binary::gf2_ext::MulWide for Gf2Ext<$params, 2> {
777 type Output = Gf2LimbsWide<2>;
778 fn mul_wide(self, rhs: Self) -> Self::Output {
779 let (low, high) =
780 $crate::algebra::ops::clmul::carry_less_mul_2limbs(self.data, rhs.data);
781 Gf2LimbsWide { low, high }
782 }
783 }
784 };
785 ($params:ty, $limbs:literal) => {
786 impl $crate::algebra::field::binary::gf2_ext::MulWide for Gf2Ext<$params, $limbs> {
787 type Output = Gf2LimbsWide<$limbs>;
788 fn mul_wide(self, rhs: Self) -> Self::Output {
789 let (low, high) = $crate::algebra::ops::clmul::carry_less_mul(self.data, rhs.data);
790 Gf2LimbsWide { low, high }
791 }
792 }
793 };
794}
795pub(crate) use impl_wide_mul;
796
797macro_rules! validate_modulus_poly_ones {
798 ([$($val:literal),+ $(,)?]) => ($(
799 static_assertions::const_assert!(($val < 64) & ($val > 0));
800 )*);
801}
802pub(crate) use validate_modulus_poly_ones;
803
804macro_rules! define_gf2_extension {
805 ($ext_name:ident, $ext_params:ident, $limbs:tt, $modulus_poly_ones:tt) => {
806 $crate::algebra::field::binary::gf2_ext::validate_modulus_poly_ones!($modulus_poly_ones);
807
808 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
809 pub struct $ext_params;
810
811 pub type $ext_name = $crate::algebra::field::binary::gf2_ext::Gf2Ext<$ext_params, $limbs>;
812
813 impl $ext_name {
815 pub fn into_ne_bytes_array(self) -> [u8; { $limbs * 8 }] {
817 bytemuck::cast(self.data)
818 }
819
820 pub fn from_ne_bytes_array(arr: [u8; { $limbs * 8 }]) -> Self {
821 Self::new(bytemuck::cast(arr))
822 }
823 }
824
825 $crate::algebra::field::binary::gf2_ext::impl_wide_mul!($ext_params, $limbs);
826
827 impl $crate::algebra::field::binary::gf2_ext::Gf2ExtParams for $ext_params {
828 type Degree = typenum::U<{ $limbs * 64 }>;
829 type Bytes = typenum::U<{ $limbs * 8 }>;
830 const POLY_MOD_ONES: &[usize] = &{ $modulus_poly_ones };
831 }
832 };
833}
834
835pub(crate) use define_gf2_extension;
836
837#[cfg(test)]
838mod tests {
839 use super::*;
840
841 const N_TESTS: usize = 1;
842
843 define_gf2_extension!(Gf2_128, Gf2_128Params, 2, [1, 2, 7]);
846 define_gf2_extension!(Gf2_192, Gf2_192Params, 3, [1, 2, 7]);
847 define_gf2_extension!(Gf2_256, Gf2_256Params, 4, [2, 5, 10]);
848 define_gf2_extension!(Gf2_64, Gf2_64Params, 1, [1, 3, 4]);
849
850 #[test]
851 fn test_gf2_ext_operations() {
852 fn gf2_operations_test_case<F: FieldExtension>() {
853 let mut rng = crate::random::test_rng();
854 for _ in 0..N_TESTS {
855 let a = F::random(&mut rng);
856 assert_eq!(a + a, F::ZERO);
858
859 assert_eq!(a * F::from(234u64), F::from(234u64) * a);
861
862 assert_eq!(a * (a + F::from(234u64)), a * a + F::from(234u64) * a);
864
865 let mut cumul = a;
867 for _ in 0..(F::Degree::to_usize()) {
868 cumul *= cumul;
869 }
870 assert_eq!(a, cumul);
871 }
872 }
873
874 gf2_operations_test_case::<Gf2_128>();
875 gf2_operations_test_case::<Gf2_256>();
876 gf2_operations_test_case::<Gf2_192>();
877 gf2_operations_test_case::<Gf2_64>();
878 }
879
880 #[test]
881 fn test_gf2_128_prod() {
882 macro_rules! gf2_128_prod_test_case {
883 ($aval:expr, $bval:expr, $prod_red:expr) => {{
884 let a: [u64; 2] = $aval;
885 let b: [u64; 2] = $bval;
886 let prod_red: [u64; 2] = $prod_red;
887
888 {
889 let ae = Gf2_128::from_limbs(a);
890 let be = Gf2_128::from_limbs(b);
891 let prod_red_comp = ae * be;
892 assert_eq!(prod_red_comp, Gf2_128::from_limbs(prod_red));
893 }
894 }};
895 }
896
897 gf2_128_prod_test_case!(
898 [0x9f418f3bffd84bba, 0x4a7c605645afdfb1],
899 [0x80b7bd91cddc5be5, 0x3a97291035e41e1f],
900 [0x46ca0b600a32c5f7, 0x823a605e0452082a]
901 );
902
903 gf2_128_prod_test_case!(
904 [0x74ef862bc1b6d333, 0x3a88103b80d97b73],
905 [0x753f4846eb020b5a, 0x8f108359ea25fa8f],
906 [0x6947ab52b94f0ef9, 0xb2ec1b5a4553aa6d]
907 );
908
909 gf2_128_prod_test_case!(
910 [0x6447b3dcaed62649, 0x6e4af40b2ee1b4c1],
911 [0xbd7a4e12fdb29840, 0x8950f56742015f25],
912 [0x38ae5eb860021fe9, 0x6f18457f05ac2506]
913 );
914 }
915}