binius_field/
binary_field_arithmetic.rs

1// Copyright 2023-2025 Irreducible Inc.
2
3use super::{arithmetic_traits::InvertOrZero, binary_field::*};
4use crate::{PackedField, arithmetic_traits::MulAlpha};
5
6pub(crate) trait TowerFieldArithmetic: TowerField {
7	fn multiply(self, rhs: Self) -> Self;
8
9	fn multiply_alpha(self) -> Self;
10
11	fn square(self) -> Self;
12}
13
14macro_rules! impl_arithmetic_using_packed {
15	($name:ident) => {
16		impl InvertOrZero for $name {
17			#[inline]
18			fn invert_or_zero(self) -> Self {
19				use $crate::as_packed_field::AsPackedField;
20
21				$crate::binary_field_arithmetic::invert_or_zero_using_packed::<
22					<Self as AsPackedField<$name>>::Packed,
23				>(self)
24			}
25		}
26
27		impl TowerFieldArithmetic for $name {
28			#[inline]
29			fn multiply(self, rhs: Self) -> Self {
30				use $crate::as_packed_field::AsPackedField;
31
32				$crate::binary_field_arithmetic::multiple_using_packed::<
33					<Self as AsPackedField<$name>>::Packed,
34				>(self, rhs)
35			}
36
37			#[inline]
38			fn multiply_alpha(self) -> Self {
39				use $crate::as_packed_field::AsPackedField;
40
41				$crate::binary_field_arithmetic::mul_alpha_using_packed::<
42					<Self as AsPackedField<$name>>::Packed,
43				>(self)
44			}
45
46			#[inline]
47			fn square(self) -> Self {
48				use $crate::as_packed_field::AsPackedField;
49
50				$crate::binary_field_arithmetic::square_using_packed::<
51					<Self as AsPackedField<$name>>::Packed,
52				>(self)
53			}
54		}
55	};
56}
57
58pub(crate) use impl_arithmetic_using_packed;
59
60// TODO: try to get rid of `TowerFieldArithmetic` and use `impl_arithmetic_using_packed` here
61impl TowerField for BinaryField1b {
62	fn min_tower_level(self) -> usize {
63		0
64	}
65
66	#[inline]
67	fn mul_primitive(self, _: usize) -> Result<Self, crate::Error> {
68		Err(crate::Error::ExtensionDegreeMismatch)
69	}
70}
71
72impl InvertOrZero for BinaryField1b {
73	#[inline]
74	fn invert_or_zero(self) -> Self {
75		self
76	}
77}
78
79impl TowerFieldArithmetic for BinaryField1b {
80	#[inline]
81	fn multiply(self, rhs: Self) -> Self {
82		Self(self.0 & rhs.0)
83	}
84
85	#[inline]
86	fn multiply_alpha(self) -> Self {
87		self
88	}
89
90	#[inline]
91	fn square(self) -> Self {
92		self
93	}
94}
95
96/// For some architectures it may be faster to used SIM versions for packed fields than to use
97/// portable single-element arithmetics. That's why we need these functions
98#[inline]
99pub(super) fn multiple_using_packed<P: PackedField>(lhs: P::Scalar, rhs: P::Scalar) -> P::Scalar {
100	(P::set_single(lhs) * P::set_single(rhs)).get(0)
101}
102
103#[inline]
104pub(super) fn square_using_packed<P: PackedField>(value: P::Scalar) -> P::Scalar {
105	P::set_single(value).square().get(0)
106}
107
108#[inline]
109pub(super) fn invert_or_zero_using_packed<P: PackedField>(value: P::Scalar) -> P::Scalar {
110	P::set_single(value).invert_or_zero().get(0)
111}
112
113#[inline]
114pub(super) fn mul_alpha_using_packed<P: PackedField + MulAlpha>(value: P::Scalar) -> P::Scalar {
115	P::set_single(value).mul_alpha().get(0)
116}