1use std::{
4 any::TypeId,
5 fmt::{Debug, Display, Formatter},
6 iter::{Product, Sum},
7 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9
10use binius_utils::{
11 bytes::{Buf, BufMut},
12 DeserializeBytes, SerializationError, SerializationMode, SerializeBytes,
13};
14use bytemuck::{Pod, Zeroable};
15use rand::RngCore;
16use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
17
18use super::{
19 binary_field_arithmetic::TowerFieldArithmetic, error::Error, extension::ExtensionField,
20};
21use crate::{
22 underlier::{U1, U2, U4},
23 Field,
24};
25
26pub trait BinaryField: ExtensionField<BinaryField1b> {
28 const N_BITS: usize = Self::DEGREE;
29 const MULTIPLICATIVE_GENERATOR: Self;
30}
31
32pub trait TowerField: BinaryField + From<Self::Canonical>
40where
41 Self::Canonical: From<Self>,
42{
43 const TOWER_LEVEL: usize = Self::N_BITS.ilog2() as usize;
45
46 type Canonical: TowerField + SerializeBytes + DeserializeBytes;
49
50 fn min_tower_level(self) -> usize;
56
57 fn basis(iota: usize, i: usize) -> Result<Self, Error> {
60 if iota > Self::TOWER_LEVEL {
61 return Err(Error::ExtensionDegreeTooHigh);
62 }
63 let n_basis_elts = 1 << (Self::TOWER_LEVEL - iota);
64 if i >= n_basis_elts {
65 return Err(Error::IndexOutOfRange {
66 index: i,
67 max: n_basis_elts,
68 });
69 }
70 <Self as ExtensionField<BinaryField1b>>::basis_checked(i << iota)
71 }
72
73 fn mul_primitive(self, iota: usize) -> Result<Self, Error> {
82 Ok(self * <Self as ExtensionField<BinaryField1b>>::basis_checked(1 << iota)?)
83 }
84}
85
86#[inline]
94pub fn ext_basis<FExt, FSub>(i: usize) -> FExt
95where
96 FSub: Field,
97 FExt: ExtensionField<FSub>,
98{
99 <FExt as ExtensionField<FSub>>::basis(i)
100}
101
102pub(super) trait TowerExtensionField:
103 TowerField
104 + ExtensionField<Self::DirectSubfield>
105 + From<(Self::DirectSubfield, Self::DirectSubfield)>
106 + Into<(Self::DirectSubfield, Self::DirectSubfield)>
107{
108 type DirectSubfield: TowerField;
109}
110
111macro_rules! binary_field {
113 ($vis:vis $name:ident($typ:ty), $gen:expr) => {
114 #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Zeroable, bytemuck::TransparentWrapper)]
115 #[repr(transparent)]
116 $vis struct $name(pub(crate) $typ);
117
118 impl $name {
119 pub const fn new(value: $typ) -> Self {
120 Self(value)
121 }
122
123 pub const fn val(self) -> $typ {
124 self.0
125 }
126 }
127
128 unsafe impl $crate::underlier::WithUnderlier for $name {
129 type Underlier = $typ;
130
131 fn to_underlier(self) -> Self::Underlier {
132 ::bytemuck::TransparentWrapper::peel(self)
133 }
134
135 fn to_underlier_ref(&self) -> &Self::Underlier {
136 ::bytemuck::TransparentWrapper::peel_ref(self)
137 }
138
139 fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier {
140 ::bytemuck::TransparentWrapper::peel_mut(self)
141 }
142
143 fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier] {
144 ::bytemuck::TransparentWrapper::peel_slice(val)
145 }
146
147 fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier] {
148 ::bytemuck::TransparentWrapper::peel_slice_mut(val)
149 }
150
151 fn from_underlier(val: Self::Underlier) -> Self {
152 ::bytemuck::TransparentWrapper::wrap(val)
153 }
154
155 fn from_underlier_ref(val: &Self::Underlier) -> &Self {
156 ::bytemuck::TransparentWrapper::wrap_ref(val)
157 }
158
159 fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self {
160 ::bytemuck::TransparentWrapper::wrap_mut(val)
161 }
162
163 fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self] {
164 ::bytemuck::TransparentWrapper::wrap_slice(val)
165 }
166
167 fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self] {
168 ::bytemuck::TransparentWrapper::wrap_slice_mut(val)
169 }
170 }
171
172 impl Neg for $name {
173 type Output = Self;
174
175 fn neg(self) -> Self::Output {
176 self
177 }
178 }
179
180 impl Add<Self> for $name {
181 type Output = Self;
182
183 #[allow(clippy::suspicious_arithmetic_impl)]
184 fn add(self, rhs: Self) -> Self::Output {
185 $name(self.0 ^ rhs.0)
186 }
187 }
188
189 impl Add<&Self> for $name {
190 type Output = Self;
191
192 #[allow(clippy::suspicious_arithmetic_impl)]
193 fn add(self, rhs: &Self) -> Self::Output {
194 $name(self.0 ^ rhs.0)
195 }
196 }
197
198 impl Sub<Self> for $name {
199 type Output = Self;
200
201 #[allow(clippy::suspicious_arithmetic_impl)]
202 fn sub(self, rhs: Self) -> Self::Output {
203 $name(self.0 ^ rhs.0)
204 }
205 }
206
207 impl Sub<&Self> for $name {
208 type Output = Self;
209
210 #[allow(clippy::suspicious_arithmetic_impl)]
211 fn sub(self, rhs: &Self) -> Self::Output {
212 $name(self.0 ^ rhs.0)
213 }
214 }
215
216 impl Mul<Self> for $name {
217 type Output = Self;
218
219 fn mul(self, rhs: Self) -> Self::Output {
220 $crate::tracing::trace_multiplication!($name);
221
222 TowerFieldArithmetic::multiply(self, rhs)
223 }
224 }
225
226 impl Mul<&Self> for $name {
227 type Output = Self;
228
229 fn mul(self, rhs: &Self) -> Self::Output {
230 self * *rhs
231 }
232 }
233
234 impl AddAssign<Self> for $name {
235 fn add_assign(&mut self, rhs: Self) {
236 *self = *self + rhs;
237 }
238 }
239
240 impl AddAssign<&Self> for $name {
241 fn add_assign(&mut self, rhs: &Self) {
242 *self = *self + *rhs;
243 }
244 }
245
246 impl SubAssign<Self> for $name {
247 fn sub_assign(&mut self, rhs: Self) {
248 *self = *self - rhs;
249 }
250 }
251
252 impl SubAssign<&Self> for $name {
253 fn sub_assign(&mut self, rhs: &Self) {
254 *self = *self - *rhs;
255 }
256 }
257
258 impl MulAssign<Self> for $name {
259 fn mul_assign(&mut self, rhs: Self) {
260 *self = *self * rhs;
261 }
262 }
263
264 impl MulAssign<&Self> for $name {
265 fn mul_assign(&mut self, rhs: &Self) {
266 *self = *self * rhs;
267 }
268 }
269
270 impl Sum<Self> for $name {
271 fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
272 iter.fold(Self::ZERO, |acc, x| acc + x)
273 }
274 }
275
276 impl<'a> Sum<&'a Self> for $name {
277 fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
278 iter.fold(Self::ZERO, |acc, x| acc + x)
279 }
280 }
281
282 impl Product<Self> for $name {
283 fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
284 iter.fold(Self::ONE, |acc, x| acc * x)
285 }
286 }
287
288 impl<'a> Product<&'a Self> for $name {
289 fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
290 iter.fold(Self::ONE, |acc, x| acc * x)
291 }
292 }
293
294 impl ConstantTimeEq for $name {
295 fn ct_eq(&self, other: &Self) -> Choice {
296 self.0.ct_eq(&other.0)
297 }
298 }
299
300 impl ConditionallySelectable for $name {
301 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
302 Self(ConditionallySelectable::conditional_select(&a.0, &b.0, choice))
303 }
304 }
305
306 impl crate::arithmetic_traits::Square for $name {
307 fn square(self) -> Self {
308 TowerFieldArithmetic::square(self)
309 }
310 }
311
312 impl Field for $name {
313 const ZERO: Self = $name::new(<$typ as $crate::underlier::UnderlierWithBitOps>::ZERO);
314 const ONE: Self = $name::new(<$typ as $crate::underlier::UnderlierWithBitOps>::ONE);
315 const CHARACTERISTIC: usize = 2;
316
317 fn random(mut rng: impl RngCore) -> Self {
318 Self(<$typ as $crate::underlier::Random>::random(&mut rng))
319 }
320
321 fn double(&self) -> Self {
322 Self::ZERO
323 }
324 }
325
326 impl Display for $name {
327 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
328 write!(f, "0x{repr:0>width$x}", repr=self.val(), width=Self::N_BITS.max(4) / 4)
329 }
330 }
331
332 impl Debug for $name {
333 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
334 let structure_name = std::any::type_name::<$name>().split("::").last().expect("exist");
335
336 write!(f, "{}({})",structure_name, self)
337 }
338 }
339
340 impl BinaryField for $name {
341 const MULTIPLICATIVE_GENERATOR: $name = $name($gen);
342 }
343
344 impl From<$typ> for $name {
345 fn from(val: $typ) -> Self {
346 return Self(val)
347 }
348 }
349
350 impl From<$name> for $typ {
351 fn from(val: $name) -> Self {
352 return val.0
353 }
354 }
355 }
356}
357
358pub(crate) use binary_field;
359
360macro_rules! binary_subfield_mul_packed_128b {
361 ($subfield_name:ident, $field_name:ident, $subfield_packed:ident) => {
362 cfg_if::cfg_if! {
363 if #[cfg(all(target_arch = "x86_64", target_feature = "gfni", target_feature = "sse2"))] {
366 impl Mul<$subfield_name> for $field_name {
367 type Output = Self;
368
369 fn mul(self, rhs: $subfield_name) -> Self::Output {
370 use bytemuck::must_cast;
371 use crate::$subfield_packed;
372
373 let a = must_cast::<_, $subfield_packed>(self);
374 must_cast(a * rhs)
375 }
376 }
377 } else {
378 impl Mul<$subfield_name> for $field_name {
379 type Output = Self;
380
381 fn mul(self, rhs: $subfield_name) -> Self::Output {
382 $crate::tracing::trace_multiplication!($field_name, $subfield_name);
383
384 let (a, b) = self.into();
385 (a * rhs, b * rhs).into()
386 }
387 }
388 }
389 }
390 };
391}
392
393pub(crate) use binary_subfield_mul_packed_128b;
394
395macro_rules! mul_by_binary_field_1b {
396 ($name:ident) => {
397 impl Mul<BinaryField1b> for $name {
398 type Output = Self;
399
400 #[inline]
401 #[allow(clippy::suspicious_arithmetic_impl)]
402 fn mul(self, rhs: BinaryField1b) -> Self::Output {
403 use $crate::underlier::{UnderlierWithBitOps, WithUnderlier};
404
405 $crate::tracing::trace_multiplication!(BinaryField128b, BinaryField1b);
406
407 Self(self.0 & <$name as WithUnderlier>::Underlier::fill_with_bit(u8::from(rhs.0)))
408 }
409 }
410 };
411}
412
413pub(crate) use mul_by_binary_field_1b;
414
415macro_rules! binary_tower_subfield_mul {
416 (BinaryField1b, $name:ident) => {
418 mul_by_binary_field_1b!($name);
419 };
420 (BinaryField8b, BinaryField128b) => {
422 $crate::binary_field::binary_subfield_mul_packed_128b!(
423 BinaryField8b,
424 BinaryField128b,
425 PackedBinaryField16x8b
426 );
427 };
428 (BinaryField16b, BinaryField128b) => {
430 $crate::binary_field::binary_subfield_mul_packed_128b!(
431 BinaryField16b,
432 BinaryField128b,
433 PackedBinaryField8x16b
434 );
435 };
436 (BinaryField32b, BinaryField128b) => {
438 $crate::binary_field::binary_subfield_mul_packed_128b!(
439 BinaryField32b,
440 BinaryField128b,
441 PackedBinaryField4x32b
442 );
443 };
444 (BinaryField64b, BinaryField128b) => {
446 $crate::binary_field::binary_subfield_mul_packed_128b!(
447 BinaryField64b,
448 BinaryField128b,
449 PackedBinaryField2x64b
450 );
451 };
452 (AESTowerField8b, AESTowerField128b) => {
454 $crate::binary_field::binary_subfield_mul_packed_128b!(
455 AESTowerField8b,
456 AESTowerField128b,
457 PackedAESBinaryField16x8b
458 );
459 };
460 (BinaryField16b, AESTowerField128b) => {
462 $crate::binary_field::binary_subfield_mul_packed_128b!(
463 AESTowerField16b,
464 AESTowerField128b,
465 PackedAESBinaryField8x16b
466 );
467 };
468 (BinaryField32b, AESTowerField128b) => {
470 $crate::binary_field::binary_subfield_mul_packed_128b!(
471 AESTowerField32b,
472 AESTowerField128b,
473 PackedAESBinaryField4x32b
474 );
475 };
476 (BinaryField64b, AESTowerField128b) => {
478 $crate::binary_field::binary_subfield_mul_packed_128b!(
479 AESTowerField64b,
480 AESTowerField128b,
481 PackedAESBinaryField2x64b
482 );
483 };
484 ($subfield_name:ident, $name:ident) => {
485 impl Mul<$subfield_name> for $name {
486 type Output = Self;
487
488 fn mul(self, rhs: $subfield_name) -> Self::Output {
489 $crate::tracing::trace_multiplication!($name, $subfield_name);
490
491 let (a, b) = self.into();
492 (a * rhs, b * rhs).into()
493 }
494 }
495 };
496}
497
498pub(crate) use binary_tower_subfield_mul;
499
500macro_rules! impl_field_extension {
501 ($subfield_name:ident($subfield_typ:ty) < @$log_degree:expr => $name:ident($typ:ty)) => {
502 impl TryFrom<$name> for $subfield_name {
503 type Error = ();
504
505 #[inline]
506 fn try_from(elem: $name) -> Result<Self, Self::Error> {
507 use $crate::underlier::NumCast;
508
509 if elem.0 >> $subfield_name::N_BITS
510 == <$typ as $crate::underlier::UnderlierWithBitOps>::ZERO
511 {
512 Ok($subfield_name::new(<$subfield_typ>::num_cast_from(elem.val())))
513 } else {
514 Err(())
515 }
516 }
517 }
518
519 impl From<$subfield_name> for $name {
520 #[inline]
521 fn from(elem: $subfield_name) -> Self {
522 $name::new(<$typ>::from(elem.val()))
523 }
524 }
525
526 impl Add<$subfield_name> for $name {
527 type Output = Self;
528
529 #[inline]
530 fn add(self, rhs: $subfield_name) -> Self::Output {
531 self + Self::from(rhs)
532 }
533 }
534
535 impl Sub<$subfield_name> for $name {
536 type Output = Self;
537
538 #[inline]
539 fn sub(self, rhs: $subfield_name) -> Self::Output {
540 self - Self::from(rhs)
541 }
542 }
543
544 impl AddAssign<$subfield_name> for $name {
545 #[inline]
546 fn add_assign(&mut self, rhs: $subfield_name) {
547 *self = *self + rhs;
548 }
549 }
550
551 impl SubAssign<$subfield_name> for $name {
552 #[inline]
553 fn sub_assign(&mut self, rhs: $subfield_name) {
554 *self = *self - rhs;
555 }
556 }
557
558 impl MulAssign<$subfield_name> for $name {
559 #[inline]
560 fn mul_assign(&mut self, rhs: $subfield_name) {
561 *self = *self * rhs;
562 }
563 }
564
565 impl Add<$name> for $subfield_name {
566 type Output = $name;
567
568 #[inline]
569 fn add(self, rhs: $name) -> Self::Output {
570 rhs + self
571 }
572 }
573
574 impl Sub<$name> for $subfield_name {
575 type Output = $name;
576
577 #[allow(clippy::suspicious_arithmetic_impl)]
578 #[inline]
579 fn sub(self, rhs: $name) -> Self::Output {
580 rhs + self
581 }
582 }
583
584 impl Mul<$name> for $subfield_name {
585 type Output = $name;
586
587 #[inline]
588 fn mul(self, rhs: $name) -> Self::Output {
589 rhs * self
590 }
591 }
592
593 impl ExtensionField<$subfield_name> for $name {
594 const LOG_DEGREE: usize = $log_degree;
595
596 #[inline]
597 fn basis_checked(i: usize) -> Result<Self, Error> {
598 use $crate::underlier::UnderlierWithBitOps;
599
600 if i >= 1 << $log_degree {
601 return Err(Error::ExtensionDegreeMismatch);
602 }
603 Ok(Self::new(<$typ>::ONE << (i * $subfield_name::N_BITS)))
604 }
605
606 #[inline]
607 fn from_bases_sparse(
608 base_elems: impl IntoIterator<Item = $subfield_name>,
609 log_stride: usize,
610 ) -> Result<Self, Error> {
611 use $crate::underlier::UnderlierWithBitOps;
612
613 debug_assert!($name::N_BITS.is_power_of_two());
614 let shift_step = ($subfield_name::N_BITS << log_stride) & ($name::N_BITS - 1);
615 let mut value = <$typ>::ZERO;
616 let mut shift = 0;
617
618 for elem in base_elems.into_iter() {
619 if shift >= $name::N_BITS {
620 return Err(Error::ExtensionDegreeMismatch);
621 }
622 value |= <$typ>::from(elem.val()) << shift;
623 shift += shift_step;
624 }
625
626 Ok(Self::new(value))
627 }
628
629 #[inline]
630 fn iter_bases(&self) -> impl Iterator<Item = $subfield_name> {
631 use $crate::underlier::{WithUnderlier, IterationMethods, IterationStrategy};
632 use binius_utils::iter::IterExtensions;
633
634 IterationMethods::<<$subfield_name as WithUnderlier>::Underlier, Self::Underlier>::ref_iter(&self.0)
635 .map_skippable($subfield_name::from)
636 }
637
638 #[inline]
639 fn into_iter_bases(self) -> impl Iterator<Item = $subfield_name> {
640 use $crate::underlier::{WithUnderlier, IterationMethods, IterationStrategy};
641 use binius_utils::iter::IterExtensions;
642
643 IterationMethods::<<$subfield_name as WithUnderlier>::Underlier, Self::Underlier>::value_iter(self.0)
644 .map_skippable($subfield_name::from)
645 }
646
647 #[inline]
648 unsafe fn get_base_unchecked(&self, i: usize) -> $subfield_name {
649 use $crate::underlier::{WithUnderlier, UnderlierWithBitOps};
650
651 $subfield_name::from_underlier(self.to_underlier().get_subvalue(i))
652 }
653 }
654 };
655}
656
657pub(crate) use impl_field_extension;
658
659pub(super) trait MulPrimitive: Sized {
662 fn mul_primitive(self, iota: usize) -> Result<Self, Error>;
663}
664
665#[macro_export]
666macro_rules! binary_tower {
667 (BinaryField1b($subfield_typ:ty $(, $canonical_subfield:ident)?) < $name:ident($typ:ty $(, $canonical:ident)?) $(< $extfield_name:ident($extfield_typ:ty $(, $canonical_ext:ident)?))+) => {
668 binary_tower!([BinaryField1b::TOWER_LEVEL]; BinaryField1b($subfield_typ $(, $canonical_subfield)?) < $name($typ $(, $canonical)?) $(< $extfield_name($extfield_typ $(, $canonical_ext)?))+);
669 };
670 ($subfield_name:ident($subfield_typ:ty $(, $canonical_subfield:ident)?) < $name:ident($typ:ty $(, $canonical:ident)?) $(< $extfield_name:ident($extfield_typ:ty $(, $canonical_ext:ident)?))+) => {
671 binary_tower!([BinaryField1b::TOWER_LEVEL, $subfield_name::TOWER_LEVEL]; $subfield_name($subfield_typ $(, $canonical_subfield)?) < $name($typ $(, $canonical)?) $(< $extfield_name($extfield_typ $(, $canonical_ext)?))+);
672 };
673 ([$($valid_tower_levels:tt)*]; $subfield_name:ident($subfield_typ:ty $(, $canonical_subfield:ident)?) < $name:ident($typ:ty)) => {
674 binary_tower!([$($valid_tower_levels)*]; $subfield_name($subfield_typ $(, $canonical_subfield)?) < $name($typ, $name));
675 };
676 ([$($valid_tower_levels:tt)*]; $subfield_name:ident($subfield_typ:ty $(, $canonical_subfield:ident)?) < $name:ident($typ:ty, $canonical:ident)) => {
677 impl From<$name> for ($subfield_name, $subfield_name) {
678 #[inline]
679 fn from(src: $name) -> ($subfield_name, $subfield_name) {
680 use $crate::underlier::NumCast;
681
682 let lo = <$subfield_typ>::num_cast_from(src.0);
683 let hi = <$subfield_typ>::num_cast_from(src.0 >> $subfield_name::N_BITS);
684 ($subfield_name::new(lo), $subfield_name::new(hi))
685 }
686 }
687
688 impl From<($subfield_name, $subfield_name)> for $name {
689 #[inline]
690 fn from((a, b): ($subfield_name, $subfield_name)) -> Self {
691 $name(<$typ>::from(a.val()) | (<$typ>::from(b.val()) << $subfield_name::N_BITS))
692 }
693 }
694
695 impl TowerField for $name {
696 const TOWER_LEVEL: usize = { $subfield_name::TOWER_LEVEL + 1 };
697
698 type Canonical = $canonical;
699
700 fn min_tower_level(self) -> usize {
701 let zero = <$typ as $crate::underlier::UnderlierWithBitOps>::ZERO;
702 for level in [$($valid_tower_levels)*] {
703 if self.0 >> (1 << level) == zero {
704 return level;
705 }
706 }
707 Self::TOWER_LEVEL
708 }
709
710 fn mul_primitive(self, iota: usize) -> Result<Self, Error> {
711 <Self as $crate::binary_field::MulPrimitive>::mul_primitive(self, iota)
712 }
713 }
714
715 impl $crate::TowerExtensionField for $name {
716 type DirectSubfield = $subfield_name;
717 }
718
719 binary_tower!($subfield_name($subfield_typ) < @1 => $name($typ));
720 };
721 ([$($valid_tower_levels:tt)*]; $subfield_name:ident($subfield_typ:ty $(, $canonical_subfield:ident)?) < $name:ident($typ:ty $(, $canonical:ident)?) $(< $extfield_name:ident($extfield_typ:ty $(, $canonical_ext:ident)?))+) => {
722 binary_tower!([$($valid_tower_levels)*]; $subfield_name($subfield_typ $(, $canonical_subfield)?) < $name($typ $(, $canonical)?));
723 binary_tower!([$($valid_tower_levels)*, $name::TOWER_LEVEL]; $name($typ $(, $canonical)?) $(< $extfield_name($extfield_typ $(, $canonical_ext)?))+);
724 binary_tower!($subfield_name($subfield_typ) < @2 => $($extfield_name($extfield_typ))<+);
725 };
726 ($subfield_name:ident($subfield_typ:ty) < @$log_degree:expr => $name:ident($typ:ty)) => {
727 $crate::binary_field::impl_field_extension!($subfield_name($subfield_typ) < @$log_degree => $name($typ));
728 $crate::binary_field::binary_tower_subfield_mul!($subfield_name, $name);
729 };
730 ($subfield_name:ident($subfield_typ:ty) < @$log_degree:expr => $name:ident($typ:ty) $(< $extfield_name:ident($extfield_typ:ty))+) => {
731 binary_tower!($subfield_name($subfield_typ) < @$log_degree => $name($typ));
732 binary_tower!($subfield_name($subfield_typ) < @$log_degree+1 => $($extfield_name($extfield_typ))<+);
733 };
734}
735
736binary_field!(pub BinaryField1b(U1), U1::new(0x1));
737binary_field!(pub BinaryField2b(U2), U2::new(0x2));
738binary_field!(pub BinaryField4b(U4), U4::new(0x5));
739binary_field!(pub BinaryField8b(u8), 0x2D);
740binary_field!(pub BinaryField16b(u16), 0xE2DE);
741binary_field!(pub BinaryField32b(u32), 0x03E21CEA);
742binary_field!(pub BinaryField64b(u64), 0x070F870DCD9C1D88);
743binary_field!(pub BinaryField128b(u128), 0x2E895399AF449ACE499596F6E5FCCAFAu128);
744
745unsafe impl Pod for BinaryField8b {}
746unsafe impl Pod for BinaryField16b {}
747unsafe impl Pod for BinaryField32b {}
748unsafe impl Pod for BinaryField64b {}
749unsafe impl Pod for BinaryField128b {}
750
751binary_tower!(
752 BinaryField1b(U1)
753 < BinaryField2b(U2)
754 < BinaryField4b(U4)
755 < BinaryField8b(u8)
756 < BinaryField16b(u16)
757 < BinaryField32b(u32)
758 < BinaryField64b(u64)
759 < BinaryField128b(u128)
760);
761
762#[inline(always)]
763pub fn is_canonical_tower<F: TowerField>() -> bool {
764 TypeId::of::<F::Canonical>() == TypeId::of::<F>()
765}
766
767macro_rules! serialize_deserialize {
768 ($bin_type:ty) => {
769 impl SerializeBytes for $bin_type {
770 fn serialize(
771 &self,
772 write_buf: impl BufMut,
773 mode: SerializationMode,
774 ) -> Result<(), SerializationError> {
775 self.0.serialize(write_buf, mode)
776 }
777 }
778
779 impl DeserializeBytes for $bin_type {
780 fn deserialize(
781 read_buf: impl Buf,
782 mode: SerializationMode,
783 ) -> Result<Self, SerializationError> {
784 Ok(Self(DeserializeBytes::deserialize(read_buf, mode)?))
785 }
786 }
787 };
788}
789
790serialize_deserialize!(BinaryField1b);
791serialize_deserialize!(BinaryField2b);
792serialize_deserialize!(BinaryField4b);
793serialize_deserialize!(BinaryField8b);
794serialize_deserialize!(BinaryField16b);
795serialize_deserialize!(BinaryField32b);
796serialize_deserialize!(BinaryField64b);
797serialize_deserialize!(BinaryField128b);
798
799impl From<BinaryField1b> for Choice {
800 fn from(val: BinaryField1b) -> Self {
801 Self::from(val.val().val())
802 }
803}
804
805impl BinaryField1b {
806 #[inline]
811 pub unsafe fn new_unchecked(val: u8) -> Self {
812 debug_assert!(val < 2);
813
814 Self::new(U1::new_unchecked(val))
815 }
816}
817
818impl From<u8> for BinaryField1b {
819 #[inline]
820 fn from(val: u8) -> Self {
821 Self::new(U1::new(val))
822 }
823}
824
825impl From<BinaryField1b> for u8 {
826 #[inline]
827 fn from(value: BinaryField1b) -> Self {
828 value.val().into()
829 }
830}
831
832impl From<bool> for BinaryField1b {
833 #[inline]
834 fn from(value: bool) -> Self {
835 Self::from(U1::new_unchecked(value.into()))
836 }
837}
838
839impl BinaryField2b {
840 #[inline]
845 pub unsafe fn new_unchecked(val: u8) -> Self {
846 debug_assert!(val < 4);
847
848 Self::new(U2::new_unchecked(val))
849 }
850}
851
852impl From<u8> for BinaryField2b {
853 #[inline]
854 fn from(val: u8) -> Self {
855 Self::new(U2::new(val))
856 }
857}
858
859impl From<BinaryField2b> for u8 {
860 #[inline]
861 fn from(value: BinaryField2b) -> Self {
862 value.val().into()
863 }
864}
865
866impl BinaryField4b {
867 #[inline]
872 pub unsafe fn new_unchecked(val: u8) -> Self {
873 debug_assert!(val < 16);
874
875 Self::new(U4::new_unchecked(val))
876 }
877}
878
879impl From<u8> for BinaryField4b {
880 #[inline]
881 fn from(val: u8) -> Self {
882 Self::new(U4::new(val))
883 }
884}
885
886impl From<BinaryField4b> for u8 {
887 #[inline]
888 fn from(value: BinaryField4b) -> Self {
889 value.val().into()
890 }
891}
892
893#[cfg(test)]
894pub(crate) mod tests {
895 use binius_utils::{bytes::BytesMut, SerializationMode};
896 use proptest::prelude::*;
897
898 use super::{
899 BinaryField16b as BF16, BinaryField1b as BF1, BinaryField2b as BF2, BinaryField4b as BF4,
900 BinaryField64b as BF64, BinaryField8b as BF8, *,
901 };
902
903 #[test]
904 fn test_gf2_add() {
905 assert_eq!(BF1::from(0) + BF1::from(0), BF1::from(0));
906 assert_eq!(BF1::from(0) + BF1::from(1), BF1::from(1));
907 assert_eq!(BF1::from(1) + BF1::from(0), BF1::from(1));
908 assert_eq!(BF1::from(1) + BF1::from(1), BF1::from(0));
909 }
910
911 #[test]
912 fn test_gf2_sub() {
913 assert_eq!(BF1::from(0) - BF1::from(0), BF1::from(0));
914 assert_eq!(BF1::from(0) - BF1::from(1), BF1::from(1));
915 assert_eq!(BF1::from(1) - BF1::from(0), BF1::from(1));
916 assert_eq!(BF1::from(1) - BF1::from(1), BF1::from(0));
917 }
918
919 #[test]
920 fn test_gf2_mul() {
921 assert_eq!(BF1::from(0) * BF1::from(0), BF1::from(0));
922 assert_eq!(BF1::from(0) * BF1::from(1), BF1::from(0));
923 assert_eq!(BF1::from(1) * BF1::from(0), BF1::from(0));
924 assert_eq!(BF1::from(1) * BF1::from(1), BF1::from(1));
925 }
926
927 #[test]
928 fn test_bin2b_mul() {
929 assert_eq!(BF2::from(0x1) * BF2::from(0x0), BF2::from(0x0));
930 assert_eq!(BF2::from(0x1) * BF2::from(0x1), BF2::from(0x1));
931 assert_eq!(BF2::from(0x0) * BF2::from(0x3), BF2::from(0x0));
932 assert_eq!(BF2::from(0x1) * BF2::from(0x2), BF2::from(0x2));
933 assert_eq!(BF2::from(0x0) * BF2::from(0x1), BF2::from(0x0));
934 assert_eq!(BF2::from(0x0) * BF2::from(0x2), BF2::from(0x0));
935 assert_eq!(BF2::from(0x1) * BF2::from(0x3), BF2::from(0x3));
936 assert_eq!(BF2::from(0x3) * BF2::from(0x0), BF2::from(0x0));
937 assert_eq!(BF2::from(0x2) * BF2::from(0x0), BF2::from(0x0));
938 assert_eq!(BF2::from(0x2) * BF2::from(0x2), BF2::from(0x3));
939 }
940
941 #[test]
942 fn test_bin4b_mul() {
943 assert_eq!(BF4::from(0x0) * BF4::from(0x0), BF4::from(0x0));
944 assert_eq!(BF4::from(0x9) * BF4::from(0x0), BF4::from(0x0));
945 assert_eq!(BF4::from(0x9) * BF4::from(0x4), BF4::from(0xa));
946 assert_eq!(BF4::from(0x6) * BF4::from(0x0), BF4::from(0x0));
947 assert_eq!(BF4::from(0x6) * BF4::from(0x7), BF4::from(0xc));
948 assert_eq!(BF4::from(0x2) * BF4::from(0x0), BF4::from(0x0));
949 assert_eq!(BF4::from(0x2) * BF4::from(0xa), BF4::from(0xf));
950 assert_eq!(BF4::from(0x1) * BF4::from(0x0), BF4::from(0x0));
951 assert_eq!(BF4::from(0x1) * BF4::from(0x8), BF4::from(0x8));
952 assert_eq!(BF4::from(0x9) * BF4::from(0xb), BF4::from(0x8));
953 }
954
955 #[test]
956 fn test_bin8b_mul() {
957 assert_eq!(BF8::new(0x00) * BF8::new(0x00), BF8::new(0x00));
958 assert_eq!(BF8::new(0x1b) * BF8::new(0xa8), BF8::new(0x09));
959 assert_eq!(BF8::new(0x00) * BF8::new(0x00), BF8::new(0x00));
960 assert_eq!(BF8::new(0x76) * BF8::new(0x51), BF8::new(0x84));
961 assert_eq!(BF8::new(0x00) * BF8::new(0x00), BF8::new(0x00));
962 assert_eq!(BF8::new(0xe4) * BF8::new(0x8f), BF8::new(0x0e));
963 assert_eq!(BF8::new(0x00) * BF8::new(0x00), BF8::new(0x00));
964 assert_eq!(BF8::new(0x42) * BF8::new(0x66), BF8::new(0xea));
965 assert_eq!(BF8::new(0x00) * BF8::new(0x00), BF8::new(0x00));
966 assert_eq!(BF8::new(0x68) * BF8::new(0xd0), BF8::new(0xc5));
967 }
968
969 #[test]
970 fn test_bin16b_mul() {
971 assert_eq!(BF16::new(0x0000) * BF16::new(0x0000), BF16::new(0x0000));
972 assert_eq!(BF16::new(0x48a8) * BF16::new(0xf8a4), BF16::new(0x3656));
973 assert_eq!(BF16::new(0xf8a4) * BF16::new(0xf8a4), BF16::new(0xe7e6));
974 assert_eq!(BF16::new(0xf8a4) * BF16::new(0xf8a4), BF16::new(0xe7e6));
975 assert_eq!(BF16::new(0x448b) * BF16::new(0x0585), BF16::new(0x47d3));
976 assert_eq!(BF16::new(0x0585) * BF16::new(0x0585), BF16::new(0x8057));
977 assert_eq!(BF16::new(0x0001) * BF16::new(0x6a57), BF16::new(0x6a57));
978 assert_eq!(BF16::new(0x0001) * BF16::new(0x0001), BF16::new(0x0001));
979 assert_eq!(BF16::new(0xf62c) * BF16::new(0x0dbd), BF16::new(0xa9da));
980 assert_eq!(BF16::new(0xf62c) * BF16::new(0xf62c), BF16::new(0x37bb));
981 }
982
983 #[test]
984 fn test_bin64b_mul() {
985 assert_eq!(
986 BF64::new(0x0000000000000000) * BF64::new(0x0000000000000000),
987 BF64::new(0x0000000000000000)
988 );
989 assert_eq!(
990 BF64::new(0xc84d619110831cef) * BF64::new(0x000000000000a14f),
991 BF64::new(0x3565086d6b9ef595)
992 );
993 assert_eq!(
994 BF64::new(0xa14f580107030300) * BF64::new(0x000000000000f404),
995 BF64::new(0x83e7239eb819a6ac)
996 );
997 assert_eq!(
998 BF64::new(0xf404210706070403) * BF64::new(0x0000000000006b44),
999 BF64::new(0x790541c54ffa2ede)
1000 );
1001 assert_eq!(
1002 BF64::new(0x6b44000404006b44) * BF64::new(0x0000000000000013),
1003 BF64::new(0x7018004c4c007018)
1004 );
1005 assert_eq!(
1006 BF64::new(0x6b44000404006b44) * BF64::new(0x0000000000000013),
1007 BF64::new(0x7018004c4c007018)
1008 );
1009 assert_eq!(
1010 BF64::new(0x6b44000404006b44) * BF64::new(0x6b44000404006b44),
1011 BF64::new(0xc59751e6f1769000)
1012 );
1013 assert_eq!(
1014 BF64::new(0x6b44000404006b44) * BF64::new(0x6b44000404006b44),
1015 BF64::new(0xc59751e6f1769000)
1016 );
1017 assert_eq!(
1018 BF64::new(0x00000000000000eb) * BF64::new(0x000000000000fba1),
1019 BF64::new(0x0000000000007689)
1020 );
1021 assert_eq!(
1022 BF64::new(0x00000000000000eb) * BF64::new(0x000000000000fba1),
1023 BF64::new(0x0000000000007689)
1024 );
1025 }
1026
1027 pub(crate) fn is_binary_field_valid_generator<F: BinaryField>() -> bool {
1028 let mut order = if F::N_BITS == 128 {
1030 u128::MAX
1031 } else {
1032 (1 << F::N_BITS) - 1
1033 };
1034
1035 let mut factorization = Vec::new();
1037
1038 let mut prime = 2;
1039 while prime * prime <= order {
1040 while order % prime == 0 {
1041 order /= prime;
1042 factorization.push(prime);
1043 }
1044
1045 prime += if prime > 2 { 2 } else { 1 };
1046 }
1047
1048 if order > 1 {
1049 factorization.push(order);
1050 }
1051
1052 for mask in 0..(1 << factorization.len()) {
1054 let mut divisor = 1;
1055
1056 for (bit_index, &prime) in factorization.iter().enumerate() {
1057 if (1 << bit_index) & mask != 0 {
1058 divisor *= prime;
1059 }
1060 }
1061
1062 divisor = divisor.reverse_bits();
1064
1065 let mut pow_divisor = F::ONE;
1066 while divisor > 0 {
1067 pow_divisor *= pow_divisor;
1068
1069 if divisor & 1 != 0 {
1070 pow_divisor *= F::MULTIPLICATIVE_GENERATOR;
1071 }
1072
1073 divisor >>= 1;
1074 }
1075
1076 let is_root_of_unity = pow_divisor == F::ONE;
1078 let is_full_group = mask + 1 == 1 << factorization.len();
1079
1080 if is_root_of_unity && !is_full_group || !is_root_of_unity && is_full_group {
1081 return false;
1082 }
1083 }
1084
1085 true
1086 }
1087
1088 #[test]
1089 fn test_multiplicative_generators() {
1090 assert!(is_binary_field_valid_generator::<BF1>());
1091 assert!(is_binary_field_valid_generator::<BF2>());
1092 assert!(is_binary_field_valid_generator::<BF4>());
1093 assert!(is_binary_field_valid_generator::<BF8>());
1094 assert!(is_binary_field_valid_generator::<BF16>());
1095 assert!(is_binary_field_valid_generator::<BinaryField32b>());
1096 assert!(is_binary_field_valid_generator::<BF64>());
1097 assert!(is_binary_field_valid_generator::<BinaryField128b>());
1098 }
1099
1100 proptest! {
1101 #[test]
1102 fn test_add_sub_subfields_is_commutative(a_val in any::<u8>(), b_val in any::<u64>()) {
1103 let (a, b) = (BinaryField8b::new(a_val), BinaryField16b::new(b_val as u16));
1104 assert_eq!(a + b, b + a);
1105 assert_eq!(a - b, -(b - a));
1106
1107 let (a, b) = (BinaryField8b::new(a_val), BinaryField64b::new(b_val));
1108 assert_eq!(a + b, b + a);
1109 assert_eq!(a - b, -(b - a));
1110 }
1111
1112 #[test]
1113 fn test_mul_subfields_is_commutative(a_val in any::<u8>(), b_val in any::<u64>()) {
1114 let (a, b) = (BinaryField8b::new(a_val), BinaryField16b::new(b_val as u16));
1115 assert_eq!(a * b, b * a);
1116
1117 let (a, b) = (BinaryField8b::new(a_val), BinaryField64b::new(b_val));
1118 assert_eq!(a * b, b * a);
1119 }
1120
1121 #[test]
1122 fn test_square_equals_mul(a_val in any::<u64>()) {
1123 let a = BinaryField64b::new(a_val);
1124 assert_eq!(a.square(), a * a);
1125 }
1126 }
1127
1128 #[test]
1129 fn test_field_degrees() {
1130 assert_eq!(BinaryField1b::N_BITS, 1);
1131 assert_eq!(BinaryField2b::N_BITS, 2);
1132 assert_eq!(BinaryField4b::N_BITS, 4);
1133 assert_eq!(<BinaryField4b as ExtensionField<BinaryField2b>>::DEGREE, 2);
1134 assert_eq!(BinaryField8b::N_BITS, 8);
1135 assert_eq!(BinaryField128b::N_BITS, 128);
1136
1137 assert_eq!(<BinaryField8b as ExtensionField<BinaryField2b>>::DEGREE, 4);
1138 assert_eq!(<BinaryField128b as ExtensionField<BinaryField2b>>::DEGREE, 64);
1139 assert_eq!(<BinaryField128b as ExtensionField<BinaryField8b>>::DEGREE, 16);
1140 }
1141
1142 #[test]
1143 fn test_field_formatting() {
1144 assert_eq!(format!("{}", BinaryField4b::from(3)), "0x3");
1145 assert_eq!(format!("{}", BinaryField8b::from(3)), "0x03");
1146 assert_eq!(format!("{}", BinaryField32b::from(5)), "0x00000005");
1147 assert_eq!(format!("{}", BinaryField64b::from(5)), "0x0000000000000005");
1148 }
1149
1150 #[test]
1151 fn test_extension_from_bases() {
1152 let a = BinaryField8b(0x01);
1153 let b = BinaryField8b(0x02);
1154 let c = BinaryField8b(0x03);
1155 let d = BinaryField8b(0x04);
1156 assert_eq!(
1157 <BinaryField32b as ExtensionField<BinaryField8b>>::from_bases([]).unwrap(),
1158 BinaryField32b(0)
1159 );
1160 assert_eq!(BinaryField32b::from_bases([a]).unwrap(), BinaryField32b(0x00000001));
1161 assert_eq!(BinaryField32b::from_bases([a, b]).unwrap(), BinaryField32b(0x00000201));
1162 assert_eq!(BinaryField32b::from_bases([a, b, c]).unwrap(), BinaryField32b(0x00030201));
1163 assert_eq!(BinaryField32b::from_bases([a, b, c, d]).unwrap(), BinaryField32b(0x04030201));
1164 assert!(BinaryField32b::from_bases([a, b, c, d, d]).is_err());
1165 }
1166
1167 #[test]
1168 fn test_inverse_on_zero() {
1169 assert!(BinaryField1b::ZERO.invert().is_none());
1170 assert!(BinaryField2b::ZERO.invert().is_none());
1171 assert!(BinaryField4b::ZERO.invert().is_none());
1172 assert!(BinaryField8b::ZERO.invert().is_none());
1173 assert!(BinaryField16b::ZERO.invert().is_none());
1174 assert!(BinaryField32b::ZERO.invert().is_none());
1175 assert!(BinaryField64b::ZERO.invert().is_none());
1176 assert!(BinaryField128b::ZERO.invert().is_none());
1177 }
1178
1179 proptest! {
1180 #[test]
1181 fn test_inverse_8b(val in 1u8..) {
1182 let x = BinaryField8b(val);
1183 let x_inverse = x.invert().unwrap();
1184 assert_eq!(x * x_inverse, BinaryField8b::ONE);
1185 }
1186
1187 #[test]
1188 fn test_inverse_32b(val in 1u32..) {
1189 let x = BinaryField32b(val);
1190 let x_inverse = x.invert().unwrap();
1191 assert_eq!(x * x_inverse, BinaryField32b::ONE);
1192 }
1193
1194 #[test]
1195 fn test_inverse_128b(val in 1u128..) {
1196 let x = BinaryField128b(val);
1197 let x_inverse = x.invert().unwrap();
1198 assert_eq!(x * x_inverse, BinaryField128b::ONE);
1199 }
1200 }
1201
1202 fn test_mul_primitive<F: TowerField>(val: F, iota: usize) {
1203 let result = val.mul_primitive(iota);
1204 let expected =
1205 <F as ExtensionField<BinaryField1b>>::basis_checked(1 << iota).map(|b| val * b);
1206 assert_eq!(result.is_ok(), expected.is_ok());
1207 if result.is_ok() {
1208 assert_eq!(result.unwrap(), expected.unwrap());
1209 } else {
1210 assert!(matches!(result.unwrap_err(), Error::ExtensionDegreeMismatch));
1211 }
1212 }
1213
1214 proptest! {
1215 #[test]
1216 fn test_mul_primitive_1b(val in 0u8..2u8, iota in 0usize..8) {
1217 test_mul_primitive::<BinaryField1b>(val.into(), iota)
1218 }
1219
1220 #[test]
1221 fn test_mul_primitive_2b(val in 0u8..4u8, iota in 0usize..8) {
1222 test_mul_primitive::<BinaryField2b>(val.into(), iota)
1223 }
1224
1225 #[test]
1226 fn test_mul_primitive_4b(val in 0u8..16u8, iota in 0usize..8) {
1227 test_mul_primitive::<BinaryField4b>(val.into(), iota)
1228 }
1229
1230 #[test]
1231 fn test_mul_primitive_8b(val in 0u8.., iota in 0usize..8) {
1232 test_mul_primitive::<BinaryField8b>(val.into(), iota)
1233 }
1234
1235 #[test]
1236 fn test_mul_primitive_16b(val in 0u16.., iota in 0usize..8) {
1237 test_mul_primitive::<BinaryField16b>(val.into(), iota)
1238 }
1239
1240 #[test]
1241 fn test_mul_primitive_32b(val in 0u32.., iota in 0usize..8) {
1242 test_mul_primitive::<BinaryField32b>(val.into(), iota)
1243 }
1244
1245 #[test]
1246 fn test_mul_primitive_64b(val in 0u64.., iota in 0usize..8) {
1247 test_mul_primitive::<BinaryField64b>(val.into(), iota)
1248 }
1249
1250 #[test]
1251 fn test_mul_primitive_128b(val in 0u128.., iota in 0usize..8) {
1252 test_mul_primitive::<BinaryField128b>(val.into(), iota)
1253 }
1254 }
1255
1256 #[test]
1257 fn test_1b_to_choice() {
1258 for i in 0..2 {
1259 assert_eq!(Choice::from(BinaryField1b::from(i)).unwrap_u8(), i);
1260 }
1261 }
1262
1263 #[test]
1264 fn test_serialization() {
1265 let mode = SerializationMode::CanonicalTower;
1266 let mut buffer = BytesMut::new();
1267 let b1 = BinaryField1b::from(0x1);
1268 let b8 = BinaryField8b::new(0x12);
1269 let b2 = BinaryField2b::from(0x2);
1270 let b16 = BinaryField16b::new(0x3456);
1271 let b32 = BinaryField32b::new(0x789ABCDE);
1272 let b4 = BinaryField4b::from(0xa);
1273 let b64 = BinaryField64b::new(0x13579BDF02468ACE);
1274 let b128 = BinaryField128b::new(0x147AD0369CF258BE8899AABBCCDDEEFF);
1275
1276 b1.serialize(&mut buffer, mode).unwrap();
1277 b8.serialize(&mut buffer, mode).unwrap();
1278 b2.serialize(&mut buffer, mode).unwrap();
1279 b16.serialize(&mut buffer, mode).unwrap();
1280 b32.serialize(&mut buffer, mode).unwrap();
1281 b4.serialize(&mut buffer, mode).unwrap();
1282 b64.serialize(&mut buffer, mode).unwrap();
1283 b128.serialize(&mut buffer, mode).unwrap();
1284
1285 let mut read_buffer = buffer.freeze();
1286
1287 assert_eq!(BinaryField1b::deserialize(&mut read_buffer, mode).unwrap(), b1);
1288 assert_eq!(BinaryField8b::deserialize(&mut read_buffer, mode).unwrap(), b8);
1289 assert_eq!(BinaryField2b::deserialize(&mut read_buffer, mode).unwrap(), b2);
1290 assert_eq!(BinaryField16b::deserialize(&mut read_buffer, mode).unwrap(), b16);
1291 assert_eq!(BinaryField32b::deserialize(&mut read_buffer, mode).unwrap(), b32);
1292 assert_eq!(BinaryField4b::deserialize(&mut read_buffer, mode).unwrap(), b4);
1293 assert_eq!(BinaryField64b::deserialize(&mut read_buffer, mode).unwrap(), b64);
1294 assert_eq!(BinaryField128b::deserialize(&mut read_buffer, mode).unwrap(), b128);
1295 }
1296
1297 #[test]
1298 fn test_gf2_new_unchecked() {
1299 for i in 0..2 {
1300 assert_eq!(unsafe { BF1::new_unchecked(i) }, BF1::from(i));
1301 }
1302 let result = std::panic::catch_unwind(|| unsafe { BF1::new_unchecked(2) });
1304 assert!(result.is_err(), "Expected a panic for value > 1, but no panic occurred");
1305 }
1306
1307 #[test]
1308 fn test_bin2b_new_unchecked() {
1309 for i in 0..4 {
1310 assert_eq!(unsafe { BF2::new_unchecked(i) }, BF2::from(i));
1311 }
1312 let result = std::panic::catch_unwind(|| unsafe { BF2::new_unchecked(4) });
1314 assert!(result.is_err(), "Expected a panic for value > 3, but no panic occurred");
1315 }
1316
1317 #[test]
1318 fn test_bin4b_new_unchecked() {
1319 for i in 0..16 {
1320 assert_eq!(unsafe { BF4::new_unchecked(i) }, BF4::from(i));
1321 }
1322 let result = std::panic::catch_unwind(|| unsafe { BF4::new_unchecked(16) });
1324 assert!(result.is_err(), "Expected a panic for value > 15, but no panic occurred");
1325 }
1326}