binius_field/arch/portable/
pairwise_recursive_arithmetic.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use crate::{
4	arch::PairwiseRecursiveStrategy,
5	arithmetic_traits::{
6		InvertOrZero, MulAlpha, Square, TaggedInvertOrZero, TaggedMul, TaggedMulAlpha, TaggedSquare,
7	},
8	packed::PackedField,
9	TowerExtensionField,
10};
11
12impl<P> TaggedMul<PairwiseRecursiveStrategy> for P
13where
14	P: PackedField,
15	P::Scalar: TowerExtensionField<DirectSubfield: MulAlpha>,
16{
17	#[inline]
18	fn mul(self, rhs: Self) -> Self {
19		P::from_fn(|i| {
20			let (a0, a1) = self.get(i).into();
21			let (b0, b1) = rhs.get(i).into();
22			let (z0, z2) = (a0 * b0, a1 * b1);
23			let z0z2 = z0 + z2;
24			let z1 = (a0 + a1) * (b0 + b1) - z0z2;
25			let z2a = MulAlpha::mul_alpha(z2);
26
27			(z0z2, z1 + z2a).into()
28		})
29	}
30}
31
32impl<P> TaggedSquare<PairwiseRecursiveStrategy> for P
33where
34	P: PackedField,
35	P::Scalar: TowerExtensionField<DirectSubfield: MulAlpha>,
36{
37	#[inline]
38	fn square(self) -> Self {
39		P::from_fn(|i| {
40			let (a0, a1) = self.get(i).into();
41			let (z0, z2) = (Square::square(a0), Square::square(a1));
42			let z2a = MulAlpha::mul_alpha(z2);
43			(z0 + z2, z2a).into()
44		})
45	}
46}
47
48impl<P> TaggedMulAlpha<PairwiseRecursiveStrategy> for P
49where
50	P: PackedField,
51	P::Scalar: TowerExtensionField<DirectSubfield: MulAlpha>,
52{
53	#[inline]
54	fn mul_alpha(self) -> Self {
55		P::from_fn(|i| {
56			let (a0, a1) = self.get(i).into();
57			let z1 = MulAlpha::mul_alpha(a1);
58
59			(a1, a0 + z1).into()
60		})
61	}
62}
63
64impl<P> TaggedInvertOrZero<PairwiseRecursiveStrategy> for P
65where
66	P: PackedField,
67	P::Scalar: TowerExtensionField<DirectSubfield: MulAlpha + InvertOrZero>,
68{
69	#[inline]
70	fn invert_or_zero(self) -> Self {
71		P::from_fn(|i| {
72			let (a0, a1) = self.get(i).into();
73			let a0z1 = a0 + MulAlpha::mul_alpha(a1);
74			let delta = a0 * a0z1 + Square::square(a1);
75			let delta_inv = InvertOrZero::invert_or_zero(delta);
76			let inv0 = delta_inv * a0z1;
77			let inv1 = delta_inv * a1;
78			(inv0, inv1).into()
79		})
80	}
81}
82
83#[cfg(test)]
84mod tests {
85	use super::*;
86	use crate::test_utils::{
87		define_invert_tests, define_mul_alpha_tests, define_multiply_tests, define_square_tests,
88	};
89
90	define_multiply_tests!(
91		TaggedMul<PairwiseRecursiveStrategy>::mul,
92		TaggedMul<PairwiseRecursiveStrategy>
93	);
94
95	define_square_tests!(
96		TaggedSquare<PairwiseRecursiveStrategy>::square,
97		TaggedSquare<PairwiseRecursiveStrategy>
98	);
99
100	define_invert_tests!(
101		TaggedInvertOrZero<PairwiseRecursiveStrategy>::invert_or_zero,
102		TaggedInvertOrZero<PairwiseRecursiveStrategy>
103	);
104
105	define_mul_alpha_tests!(
106		TaggedMulAlpha<PairwiseRecursiveStrategy>::mul_alpha,
107		TaggedMulAlpha<PairwiseRecursiveStrategy>
108	);
109}