binius_field/
binary_field_arithmetic.rs

1// Copyright 2023-2025 Irreducible Inc.
2
3use super::{arithmetic_traits::InvertOrZero, binary_field::*};
4use crate::{arithmetic_traits::MulAlpha, PackedField};
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	type Canonical = Self;
63
64	fn min_tower_level(self) -> usize {
65		0
66	}
67
68	#[inline]
69	fn mul_primitive(self, _: usize) -> Result<Self, crate::Error> {
70		Err(crate::Error::ExtensionDegreeMismatch)
71	}
72}
73
74impl InvertOrZero for BinaryField1b {
75	#[inline]
76	fn invert_or_zero(self) -> Self {
77		self
78	}
79}
80
81impl TowerFieldArithmetic for BinaryField1b {
82	#[inline]
83	fn multiply(self, rhs: Self) -> Self {
84		Self(self.0 & rhs.0)
85	}
86
87	#[inline]
88	fn multiply_alpha(self) -> Self {
89		self
90	}
91
92	#[inline]
93	fn square(self) -> Self {
94		self
95	}
96}
97
98impl_arithmetic_using_packed!(BinaryField2b);
99impl_arithmetic_using_packed!(BinaryField4b);
100impl_arithmetic_using_packed!(BinaryField8b);
101impl_arithmetic_using_packed!(BinaryField16b);
102impl_arithmetic_using_packed!(BinaryField32b);
103impl_arithmetic_using_packed!(BinaryField64b);
104impl_arithmetic_using_packed!(BinaryField128b);
105
106/// For some architectures it may be faster to used SIM versions for packed fields than to use portable
107/// single-element arithmetics. That's why we need these functions
108#[inline]
109pub(super) fn multiple_using_packed<P: PackedField>(lhs: P::Scalar, rhs: P::Scalar) -> P::Scalar {
110	(P::set_single(lhs) * P::set_single(rhs)).get(0)
111}
112
113#[inline]
114pub(super) fn square_using_packed<P: PackedField>(value: P::Scalar) -> P::Scalar {
115	P::set_single(value).square().get(0)
116}
117
118#[inline]
119pub(super) fn invert_or_zero_using_packed<P: PackedField>(value: P::Scalar) -> P::Scalar {
120	P::set_single(value).invert_or_zero().get(0)
121}
122
123#[inline]
124pub(super) fn mul_alpha_using_packed<P: PackedField + MulAlpha>(value: P::Scalar) -> P::Scalar {
125	P::set_single(value).mul_alpha().get(0)
126}
127
128// `MulPrimitive` implementation for binary tower
129
130/// Multiply `val` by alpha as a packed field with `smaller_type` scalar
131macro_rules! mul_alpha_as_repacked {
132	($val:ident, $source_type:ty, $smaller_type:ty) => {{
133		use $crate::as_packed_field::AsPackedField;
134
135		let repacked_value = <$source_type as AsPackedField<$smaller_type>>::to_packed($val);
136		<$source_type as AsPackedField<$smaller_type>>::from_packed(
137			$crate::arithmetic_traits::MulAlpha::mul_alpha(repacked_value),
138		)
139	}};
140}
141
142pub(super) use mul_alpha_as_repacked;
143
144macro_rules! impl_mul_primitive {
145	($name:ty, $(mul_by $height_0:literal => $expr:expr,)* $(repack $height_1:literal => $subtype:ty,)*) => {
146		impl $crate::binary_field::MulPrimitive for $name {
147			#[inline]
148			fn mul_primitive(self, iota: usize) -> Result<Self, $crate::Error> {
149				match iota {
150					$($height_0 => Ok(self * $expr),)*
151					$($height_1 => {
152						let result = $crate::binary_field_arithmetic::mul_alpha_as_repacked!(self, $name, $subtype);
153						Ok(result)
154					},)*
155					_ => Err($crate::Error::ExtensionDegreeMismatch),
156				}
157			}
158		}
159	};
160}
161
162pub(super) use impl_mul_primitive;
163
164impl_mul_primitive!(BinaryField2b,
165	repack 0 => BinaryField2b,
166);
167impl_mul_primitive!(BinaryField4b,
168	repack 0 => BinaryField2b,
169	repack 1 => BinaryField4b,
170);
171impl_mul_primitive!(BinaryField8b,
172	repack 0 => BinaryField2b,
173	repack 1 => BinaryField4b,
174	repack 2 => BinaryField8b,
175);
176impl_mul_primitive!(BinaryField16b,
177	repack 0 => BinaryField2b,
178	repack 1 => BinaryField4b,
179	repack 2 => BinaryField8b,
180	repack 3 => BinaryField16b,
181);
182impl_mul_primitive!(BinaryField32b,
183	repack 0 => BinaryField2b,
184	repack 1 => BinaryField4b,
185	repack 2 => BinaryField8b,
186	repack 3 => BinaryField16b,
187	repack 4 => BinaryField32b,
188);
189impl_mul_primitive!(BinaryField64b,
190	repack 0 => BinaryField2b,
191	repack 1 => BinaryField4b,
192	repack 2 => BinaryField8b,
193	repack 3 => BinaryField16b,
194	repack 4 => BinaryField32b,
195	repack 5 => BinaryField64b,
196);
197impl_mul_primitive!(BinaryField128b,
198	repack 0 => BinaryField2b,
199	repack 1 => BinaryField4b,
200	repack 2 => BinaryField8b,
201	repack 3 => BinaryField16b,
202	repack 4 => BinaryField32b,
203	repack 5 => BinaryField64b,
204	repack 6 => BinaryField128b,
205);