1pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign};
4
5use crypto_bigint::Integer;
6use group::Group;
7use subtle::{Choice, ConditionallySelectable, CtOption};
8
9#[cfg(feature = "alloc")]
10use alloc::vec::Vec;
11
12pub trait Invert {
14    type Output;
16
17    fn invert(&self) -> Self::Output;
19
20    fn invert_vartime(&self) -> Self::Output {
27        self.invert()
29    }
30}
31
32pub trait BatchInvert<FieldElements: ?Sized>: Invert + Sized {
35    type Output: AsRef<[Self]>;
37
38    fn batch_invert(
40        field_elements: &FieldElements,
41    ) -> CtOption<<Self as BatchInvert<FieldElements>>::Output>;
42}
43
44impl<const N: usize, T> BatchInvert<[T; N]> for T
45where
46    T: Invert<Output = CtOption<Self>>
47        + Mul<Self, Output = Self>
48        + Copy
49        + Default
50        + ConditionallySelectable,
51{
52    type Output = [Self; N];
53
54    fn batch_invert(field_elements: &[Self; N]) -> CtOption<[Self; N]> {
55        let mut field_elements_multiples = [Self::default(); N];
56        let mut field_elements_multiples_inverses = [Self::default(); N];
57        let mut field_elements_inverses = [Self::default(); N];
58
59        let inversion_succeeded = invert_batch_internal(
60            field_elements,
61            &mut field_elements_multiples,
62            &mut field_elements_multiples_inverses,
63            &mut field_elements_inverses,
64        );
65
66        CtOption::new(field_elements_inverses, inversion_succeeded)
67    }
68}
69
70#[cfg(feature = "alloc")]
71impl<T> BatchInvert<[T]> for T
72where
73    T: Invert<Output = CtOption<Self>>
74        + Mul<Self, Output = Self>
75        + Copy
76        + Default
77        + ConditionallySelectable,
78{
79    type Output = Vec<Self>;
80
81    fn batch_invert(field_elements: &[Self]) -> CtOption<Vec<Self>> {
82        let mut field_elements_multiples: Vec<Self> = vec![Self::default(); field_elements.len()];
83        let mut field_elements_multiples_inverses: Vec<Self> =
84            vec![Self::default(); field_elements.len()];
85        let mut field_elements_inverses: Vec<Self> = vec![Self::default(); field_elements.len()];
86
87        let inversion_succeeded = invert_batch_internal(
88            field_elements,
89            field_elements_multiples.as_mut(),
90            field_elements_multiples_inverses.as_mut(),
91            field_elements_inverses.as_mut(),
92        );
93
94        CtOption::new(
95            field_elements_inverses.into_iter().collect(),
96            inversion_succeeded,
97        )
98    }
99}
100
101fn invert_batch_internal<
108    T: Invert<Output = CtOption<T>> + Mul<T, Output = T> + Default + ConditionallySelectable,
109>(
110    field_elements: &[T],
111    field_elements_multiples: &mut [T],
112    field_elements_multiples_inverses: &mut [T],
113    field_elements_inverses: &mut [T],
114) -> Choice {
115    let batch_size = field_elements.len();
116    if batch_size == 0
117        || batch_size != field_elements_multiples.len()
118        || batch_size != field_elements_multiples_inverses.len()
119    {
120        return Choice::from(0);
121    }
122
123    field_elements_multiples[0] = field_elements[0];
124    for i in 1..batch_size {
125        field_elements_multiples[i] = field_elements_multiples[i - 1] * field_elements[i];
127    }
128
129    field_elements_multiples[batch_size - 1]
130        .invert()
131        .map(|multiple_of_inverses_of_all_field_elements| {
132            field_elements_multiples_inverses[batch_size - 1] =
133                multiple_of_inverses_of_all_field_elements;
134            for i in (1..batch_size).rev() {
135                field_elements_multiples_inverses[i - 1] =
137                    field_elements_multiples_inverses[i] * field_elements[i];
138            }
139
140            field_elements_inverses[0] = field_elements_multiples_inverses[0];
141            for i in 1..batch_size {
142                field_elements_inverses[i] =
144                    field_elements_multiples_inverses[i] * field_elements_multiples[i - 1];
145            }
146        })
147        .is_some()
148}
149
150pub trait LinearCombination: Group {
157    fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
159        (*x * k) + (*y * l)
160    }
161}
162
163pub trait LinearCombinationExt<PointsAndScalars>: group::Curve
169where
170    PointsAndScalars: AsRef<[(Self, Self::Scalar)]> + ?Sized,
171{
172    fn lincomb_ext(points_and_scalars: &PointsAndScalars) -> Self {
174        points_and_scalars
175            .as_ref()
176            .iter()
177            .copied()
178            .map(|(point, scalar)| point * scalar)
179            .sum()
180    }
181}
182
183impl<P: LinearCombinationExt<[(P, Self::Scalar); 2]>> LinearCombination for P {
186    fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
187        Self::lincomb_ext(&[(*x, *k), (*y, *l)])
188    }
189}
190
191pub trait MulByGenerator: Group {
196    #[must_use]
198    fn mul_by_generator(scalar: &Self::Scalar) -> Self {
199        Self::generator() * scalar
200    }
201}
202
203pub trait Reduce<Uint: Integer>: Sized {
205    type Bytes: AsRef<[u8]>;
207
208    fn reduce(n: Uint) -> Self;
210
211    fn reduce_bytes(bytes: &Self::Bytes) -> Self;
213}
214
215pub trait ReduceNonZero<Uint: Integer>: Reduce<Uint> + Sized {
223    fn reduce_nonzero(n: Uint) -> Self;
225
226    fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self;
229}