primitives/algebra/field/binary/
gf2_128_field.rs1use std::{
2 iter::{Product, Sum},
3 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
4};
5
6use ff::Field;
7use hybrid_array::Array;
8use rand::RngCore;
9use serde::{Deserialize, Serialize};
10use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
11use typenum::{U1, U128, U16};
12use wincode::{SchemaRead, SchemaWrite};
13
14use crate::{
15 algebra::{
16 field::{
17 binary::{
18 gf2_ext::{Gf2LimbsWide, MulWide},
19 Gf2_128,
20 },
21 FieldExtension,
22 },
23 ops::{AccReduce, DefaultDotProduct, IntoWide, MulAccReduce, ReduceWide},
24 uniform_bytes::FromUniformBytes,
25 },
26 random::{CryptoRngCore, Random},
27 types::{HeapArray, Positive},
28};
29
30#[derive(
40 Copy,
41 Clone,
42 Default,
43 Debug,
44 PartialEq,
45 Eq,
46 Hash,
47 PartialOrd,
48 Ord,
49 Serialize,
50 Deserialize,
51 SchemaRead,
52 SchemaWrite,
53)]
54#[serde(transparent)]
55#[repr(transparent)]
56pub struct Gf2_128Field(pub Gf2_128);
57
58#[macros::op_variants(owned)]
63impl<'a> MulAssign<&'a Gf2_128Field> for Gf2_128Field {
64 #[inline]
65 fn mul_assign(&mut self, rhs: &'a Gf2_128Field) {
66 self.0 *= rhs.0;
67 }
68}
69
70#[macros::op_variants(owned)]
71impl<'a> Mul<&'a Gf2_128Field> for Gf2_128Field {
72 type Output = Self;
73
74 #[inline]
75 fn mul(mut self, rhs: &'a Gf2_128Field) -> Self::Output {
76 self.mul_assign(rhs);
77 self
78 }
79}
80
81#[macros::op_variants(owned)]
82impl<'a> AddAssign<&'a Gf2_128Field> for Gf2_128Field {
83 #[inline]
84 fn add_assign(&mut self, rhs: &'a Gf2_128Field) {
85 self.0 += rhs.0;
86 }
87}
88
89#[macros::op_variants(owned)]
90impl<'a> Add<&'a Gf2_128Field> for Gf2_128Field {
91 type Output = Self;
92
93 #[inline]
94 fn add(mut self, rhs: &'a Gf2_128Field) -> Self::Output {
95 self.add_assign(rhs);
96 self
97 }
98}
99
100#[macros::op_variants(owned)]
101impl<'a> SubAssign<&'a Gf2_128Field> for Gf2_128Field {
102 #[inline]
103 fn sub_assign(&mut self, rhs: &'a Gf2_128Field) {
104 self.0 -= rhs.0;
105 }
106}
107
108#[macros::op_variants(owned)]
109impl<'a> Sub<&'a Gf2_128Field> for Gf2_128Field {
110 type Output = Self;
111
112 #[inline]
113 fn sub(mut self, rhs: &'a Gf2_128Field) -> Self::Output {
114 self.sub_assign(rhs);
115 self
116 }
117}
118
119#[macros::op_variants(borrowed)]
120impl Neg for Gf2_128Field {
121 type Output = Gf2_128Field;
122
123 #[inline]
124 fn neg(self) -> Self::Output {
125 self
126 }
127}
128
129impl Sum for Gf2_128Field {
130 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
131 iter.fold(<Self as Field>::ZERO, |acc, x| acc + x)
132 }
133}
134
135impl<'a> Sum<&'a Self> for Gf2_128Field {
136 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
137 iter.fold(<Self as Field>::ZERO, |acc, x| acc + x)
138 }
139}
140
141impl Product for Gf2_128Field {
142 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
143 iter.fold(<Self as Field>::ONE, |acc, x| acc * x)
144 }
145}
146
147impl<'a> Product<&'a Self> for Gf2_128Field {
148 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
149 iter.fold(<Self as Field>::ONE, |acc, x| acc * x)
150 }
151}
152
153impl ConditionallySelectable for Gf2_128Field {
158 #[inline]
159 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
160 Self(Gf2_128::conditional_select(&a.0, &b.0, choice))
161 }
162}
163
164impl ConstantTimeEq for Gf2_128Field {
165 #[inline]
166 fn ct_eq(&self, other: &Self) -> Choice {
167 self.0.ct_eq(&other.0)
168 }
169}
170
171impl Field for Gf2_128Field {
176 const ZERO: Self = Self(<Gf2_128 as Field>::ZERO);
177 const ONE: Self = Self(<Gf2_128 as Field>::ONE);
178
179 fn random(rng: impl RngCore) -> Self {
180 Self(<Gf2_128 as Field>::random(rng))
181 }
182
183 fn square(&self) -> Self {
184 Self(self.0.square())
185 }
186
187 fn double(&self) -> Self {
188 Self(self.0.double())
189 }
190
191 fn invert(&self) -> CtOption<Self> {
192 self.0.invert().map(Self)
193 }
194
195 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
196 let (is_valid, root) = Gf2_128::sqrt_ratio(&num.0, &div.0);
197 (is_valid, Self(root))
198 }
199
200 fn sqrt(&self) -> CtOption<Self> {
201 self.0.sqrt().map(Self)
202 }
203}
204
205impl FieldExtension for Gf2_128Field {
206 type Subfield = Self;
207 type Degree = U1;
208 type FieldBitSize = U128;
209 type FieldBytesSize = U16;
210
211 fn to_subfield_elements(&self) -> Array<Self::Subfield, Self::Degree> {
212 Array([*self])
213 }
214
215 fn from_subfield_elements(elems: Array<Self::Subfield, Self::Degree>) -> Self {
216 elems[0]
217 }
218
219 fn to_le_bytes(&self) -> Array<u8, Self::FieldBytesSize> {
220 self.0.to_le_bytes()
221 }
222
223 fn from_le_bytes(bytes: &[u8]) -> Option<Self> {
224 Gf2_128::from_le_bytes(bytes).map(Self)
225 }
226
227 fn mul_by_subfield(&self, other: &Self::Subfield) -> Self {
228 *self * other
229 }
230
231 fn generator() -> Self {
232 Self(Gf2_128::generator())
233 }
234
235 fn linear_orthomorphism(&self) -> Self {
238 Self(self.0.linear_orthomorphism())
239 }
240}
241
242impl Random for Gf2_128Field {
243 fn random(rng: impl CryptoRngCore) -> Self {
244 Self(Random::random(rng))
245 }
246
247 fn random_array<M: Positive>(mut rng: impl CryptoRngCore) -> HeapArray<Self, M> {
248 let mut buf = HeapArray::<Self, M>::default().into_box_bytes();
249 rng.fill_bytes(&mut buf);
250 HeapArray::from_box_bytes(buf)
251 }
252}
253
254unsafe impl bytemuck::Zeroable for Gf2_128Field {}
255unsafe impl bytemuck::Pod for Gf2_128Field {}
256
257impl FromUniformBytes for Gf2_128Field {
258 type UniformBytes = U16;
259
260 fn from_uniform_bytes(bytes: &Array<u8, Self::UniformBytes>) -> Self {
261 Self(Gf2_128::from_uniform_bytes(bytes))
262 }
263}
264
265impl From<u64> for Gf2_128Field {
266 fn from(val: u64) -> Self {
267 Self(Gf2_128::from(val))
268 }
269}
270
271impl From<u128> for Gf2_128Field {
272 fn from(val: u128) -> Self {
273 Self(Gf2_128::from(val))
274 }
275}
276
277impl IntoWide<Gf2LimbsWide<2>> for Gf2_128Field {
282 #[inline]
283 fn to_wide(&self) -> Gf2LimbsWide<2> {
284 <Gf2_128 as IntoWide<Gf2LimbsWide<2>>>::to_wide(&self.0)
285 }
286
287 #[inline]
288 fn zero_wide() -> Gf2LimbsWide<2> {
289 <Gf2_128 as IntoWide<Gf2LimbsWide<2>>>::zero_wide()
290 }
291}
292
293impl ReduceWide<Gf2LimbsWide<2>> for Gf2_128Field {
294 #[inline]
295 fn reduce_mod_order(a: Gf2LimbsWide<2>) -> Self {
296 Self(Gf2_128::reduce_mod_order(a))
297 }
298}
299
300impl IntoWide for Gf2_128Field {
301 #[inline]
302 fn to_wide(&self) -> Self {
303 *self
304 }
305
306 #[inline]
307 fn zero_wide() -> Self {
308 <Self as Field>::ZERO
309 }
310}
311
312impl ReduceWide for Gf2_128Field {
313 #[inline]
314 fn reduce_mod_order(a: Self) -> Self {
315 a
316 }
317}
318
319impl MulAccReduce for Gf2_128Field {
320 type WideType = Gf2LimbsWide<2>;
321
322 #[inline]
323 fn mul_acc(acc: &mut Self::WideType, a: Self, b: Self) {
324 *acc += a.0.mul_wide(b.0);
325 }
326}
327
328impl MulAccReduce<Self, &Self> for Gf2_128Field {
329 type WideType = Gf2LimbsWide<2>;
330
331 #[inline]
332 fn mul_acc(acc: &mut Self::WideType, a: Self, b: &Self) {
333 <Self as MulAccReduce>::mul_acc(acc, a, *b);
334 }
335}
336
337impl MulAccReduce<&Self, Self> for Gf2_128Field {
338 type WideType = Gf2LimbsWide<2>;
339
340 #[inline]
341 fn mul_acc(acc: &mut Self::WideType, a: &Self, b: Self) {
342 <Self as MulAccReduce>::mul_acc(acc, *a, b);
343 }
344}
345
346impl MulAccReduce<&Self, &Self> for Gf2_128Field {
347 type WideType = Gf2LimbsWide<2>;
348
349 #[inline]
350 fn mul_acc(acc: &mut Self::WideType, a: &Self, b: &Self) {
351 <Self as MulAccReduce>::mul_acc(acc, *a, *b);
352 }
353}
354
355impl AccReduce for Gf2_128Field {
356 type WideType = Self;
357
358 #[inline]
359 fn acc(acc: &mut Self, a: Self) {
360 *acc += a;
361 }
362}
363
364impl AccReduce<&Self> for Gf2_128Field {
365 type WideType = Self;
366
367 #[inline]
368 fn acc(acc: &mut Self, a: &Self) {
369 *acc += a;
370 }
371}
372
373impl DefaultDotProduct for Gf2_128Field {}
374impl DefaultDotProduct<Self, &Self> for Gf2_128Field {}
375impl DefaultDotProduct<&Self, Self> for Gf2_128Field {}
376impl DefaultDotProduct<&Self, &Self> for Gf2_128Field {}
377
378#[cfg(test)]
379mod test {
380 use ff::Field;
381 use subtle::ConstantTimeEq;
382 use typenum::Unsigned;
383
384 use super::Gf2_128Field;
385 use crate::{
386 algebra::{field::FieldExtension, ops::DotProduct},
387 random::{test_rng, Random},
388 };
389
390 type M = typenum::U100;
391
392 #[test]
393 fn test_field_axioms() {
394 let mut rng = test_rng();
395 for _ in 0..M::to_usize() {
396 let a: Gf2_128Field = Random::random(&mut rng);
397 let b: Gf2_128Field = Random::random(&mut rng);
398
399 assert_eq!(a + a, Gf2_128Field::ZERO);
401 assert_eq!(-a, a);
402 assert_eq!(a - b, a + b);
403
404 assert_eq!(a * (a + b), a * a + a * b);
406
407 let mut cumul = a;
409 for _ in 0..128 {
410 cumul *= cumul;
411 }
412 assert_eq!(a, cumul);
413 }
414 }
415
416 #[test]
417 fn test_invert_and_sqrt() {
418 let mut rng = test_rng();
419
420 assert!(bool::from(Gf2_128Field::ZERO.invert().is_none()));
421
422 for _ in 0..M::to_usize() {
423 let a: Gf2_128Field = Random::random(&mut rng);
424 if bool::from(a.is_zero()) {
425 continue;
426 }
427 assert_eq!(a * a.invert().unwrap(), Gf2_128Field::ONE);
428
429 let root = a.sqrt().unwrap();
430 assert_eq!(root * root, a);
431
432 let (is_valid, ratio_root) = Gf2_128Field::sqrt_ratio_ext(&Gf2_128Field::ONE, &a);
433 assert!(bool::from(is_valid));
434 assert_eq!(ratio_root * ratio_root * a, Gf2_128Field::ONE);
435 }
436 }
437
438 #[test]
439 fn test_linear_orthomorphism() {
440 let mut rng = test_rng();
443 for _ in 0..M::to_usize() {
444 let a: Gf2_128Field = Random::random(&mut rng);
445 if bool::from(a.is_zero()) {
446 continue;
447 }
448 let sigma = a.linear_orthomorphism();
449 assert_ne!(sigma, Gf2_128Field::ZERO);
450 assert_ne!(sigma + a, Gf2_128Field::ZERO);
451 }
452 }
453
454 #[test]
455 fn test_byte_roundtrips() {
456 let mut rng = test_rng();
457 for _ in 0..M::to_usize() {
458 let a: Gf2_128Field = Random::random(&mut rng);
459
460 let bytes = a.to_le_bytes();
461 assert_eq!(Gf2_128Field::from_le_bytes(&bytes), Some(a));
462
463 let serialized = bincode::serialize(&a).unwrap();
464 assert_eq!(
465 bincode::deserialize::<Gf2_128Field>(&serialized).unwrap(),
466 a
467 );
468
469 let written = wincode::serialize(&a).unwrap();
470 assert_eq!(wincode::deserialize::<Gf2_128Field>(&written).unwrap(), a);
471 }
472 }
473
474 #[test]
475 fn test_dot_product() {
476 let mut rng = test_rng();
477 let a = Gf2_128Field::random_array::<typenum::U13>(&mut rng);
478 let b = Gf2_128Field::random_array::<typenum::U13>(&mut rng);
479
480 let expected = a
481 .iter()
482 .zip(b.iter())
483 .fold(Gf2_128Field::ZERO, |acc, (x, y)| acc + *x * y);
484 let actual = Gf2_128Field::dot(a, b);
485 assert_eq!(expected, actual);
486
487 assert_eq!(
488 Gf2_128Field::ZERO,
489 Gf2_128Field::dot(
490 std::iter::empty::<Gf2_128Field>(),
491 std::iter::empty::<Gf2_128Field>()
492 )
493 );
494 }
495
496 #[test]
497 fn test_constant_time_eq() {
498 let a = Gf2_128Field::from(42u64);
499 assert!(bool::from(a.ct_eq(&Gf2_128Field::from(42u64))));
500 assert!(!bool::from(a.ct_eq(&Gf2_128Field::from(43u64))));
501 }
502}