1pub use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Shr, ShrAssign, Sub, SubAssign};
4pub use crypto_bigint::Invert;
5
6use crate::CurveGroup;
7use core::iter;
8use crypto_bigint::Integer;
9use ff::Field;
10use subtle::{Choice, CtOption};
11
12#[cfg(feature = "alloc")]
13use alloc::{borrow::ToOwned, vec::Vec};
14
15pub trait BatchInvert<FieldElements: ?Sized> {
18 type Output;
20
21 fn batch_invert(field_elements: FieldElements) -> <Self as BatchInvert<FieldElements>>::Output;
23}
24
25impl<const N: usize, T> BatchInvert<[T; N]> for T
26where
27 T: Field,
28{
29 type Output = CtOption<[Self; N]>;
30
31 fn batch_invert(mut field_elements: [Self; N]) -> CtOption<[Self; N]> {
32 let mut field_elements_pad = [Self::default(); N];
33 let inversion_succeeded =
34 invert_batch_internal(&mut field_elements, &mut field_elements_pad, invert);
35
36 CtOption::new(field_elements, inversion_succeeded)
37 }
38}
39
40#[cfg(feature = "alloc")]
41impl<'this, T> BatchInvert<&'this mut [Self]> for T
42where
43 T: Field,
44{
45 type Output = CtOption<&'this mut [Self]>;
46
47 fn batch_invert(field_elements: &'this mut [Self]) -> CtOption<&'this mut [Self]> {
48 let mut field_elements_pad: Vec<Self> = vec![Self::default(); field_elements.len()];
49 let inversion_succeeded =
50 invert_batch_internal(field_elements, &mut field_elements_pad, invert);
51
52 CtOption::new(field_elements, inversion_succeeded)
53 }
54}
55
56#[cfg(feature = "alloc")]
57impl<T> BatchInvert<&[Self]> for T
58where
59 T: Field,
60{
61 type Output = CtOption<Vec<Self>>;
62
63 fn batch_invert(field_elements: &[Self]) -> CtOption<Vec<Self>> {
64 let mut field_elements: Vec<Self> = field_elements.to_owned();
65 let mut field_elements_pad: Vec<Self> = vec![Self::default(); field_elements.len()];
66 let inversion_succeeded =
67 invert_batch_internal(&mut field_elements, &mut field_elements_pad, invert);
68
69 CtOption::new(field_elements, inversion_succeeded)
70 }
71}
72
73#[cfg(feature = "alloc")]
74impl<T> BatchInvert<Vec<Self>> for T
75where
76 T: Field,
77{
78 type Output = CtOption<Vec<Self>>;
79
80 fn batch_invert(mut field_elements: Vec<Self>) -> CtOption<Vec<Self>> {
81 let mut field_elements_pad: Vec<Self> = vec![Self::default(); field_elements.len()];
82 let inversion_succeeded =
83 invert_batch_internal(&mut field_elements, &mut field_elements_pad, invert);
84
85 CtOption::new(field_elements, inversion_succeeded)
86 }
87}
88
89fn invert<T: Field>(scalar: T) -> (T, Choice) {
90 let scalar = scalar.invert();
91 let choice = scalar.is_some();
92 let scalar = scalar.unwrap_or(T::default());
93
94 (scalar, choice)
95}
96
97pub(crate) fn invert_batch_internal<T: Copy + Mul<Output = T> + MulAssign>(
104 field_elements: &mut [T],
105 field_elements_pad: &mut [T],
106 invert: fn(T) -> (T, Choice),
107) -> Choice {
108 let batch_size = field_elements.len();
109 if batch_size != field_elements_pad.len() {
110 return Choice::from(0);
111 }
112 if batch_size == 0 {
113 return Choice::from(1);
114 }
115
116 let mut acc = field_elements[0];
117 field_elements_pad[0] = acc;
118
119 for (field_element, field_element_pad) in field_elements
120 .iter_mut()
121 .zip(field_elements_pad.iter_mut())
122 .skip(1)
123 {
124 acc *= *field_element;
126 *field_element_pad = acc;
127 }
128
129 let (mut acc, choice) = invert(acc);
130
131 let field_elements_pad = field_elements_pad
133 .iter()
134 .rev()
135 .skip(1)
136 .map(Some)
137 .chain(iter::once(None));
138
139 for (field_element, field_element_pad) in
140 field_elements.iter_mut().rev().zip(field_elements_pad)
141 {
142 if let Some(field_element_pad) = field_element_pad {
143 let tmp = acc * *field_element;
146 *field_element = acc * *field_element_pad;
148 acc = tmp;
149 } else {
150 *field_element = acc;
151 }
152 }
153
154 choice
155}
156
157pub trait LinearCombination<PointsAndScalars>: CurveGroup
164where
165 PointsAndScalars: AsRef<[(Self, Self::Scalar)]> + ?Sized,
166{
167 fn lincomb(points_and_scalars: &PointsAndScalars) -> Self {
169 points_and_scalars
170 .as_ref()
171 .iter()
172 .copied()
173 .map(|(point, scalar)| point * scalar)
174 .sum()
175 }
176}
177
178pub trait Reduce<Uint: Integer>: Sized {
180 type Bytes: AsRef<[u8]>;
182
183 fn reduce(n: Uint) -> Self;
185
186 fn reduce_bytes(bytes: &Self::Bytes) -> Self;
188}
189
190pub trait ReduceNonZero<Uint: Integer>: Reduce<Uint> + Sized {
198 fn reduce_nonzero(n: Uint) -> Self;
200
201 fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self;
204}