snarkvm_console_types_field/
arithmetic.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<E: Environment> Neg for Field<E> {
19    type Output = Field<E>;
20
21    /// Returns the `negation` of `self`.
22    #[inline]
23    fn neg(self) -> Self::Output {
24        Field::new(-self.field)
25    }
26}
27
28impl<E: Environment> Add<Field<E>> for Field<E> {
29    type Output = Field<E>;
30
31    /// Returns the `sum` of `self` and `other`.
32    #[inline]
33    fn add(self, other: Field<E>) -> Self::Output {
34        Field::new(self.field + other.field)
35    }
36}
37
38impl<E: Environment> Add<&Field<E>> for Field<E> {
39    type Output = Field<E>;
40
41    /// Returns the `sum` of `self` and `other`.
42    #[inline]
43    fn add(self, other: &Field<E>) -> Self::Output {
44        Field::new(self.field + other.field)
45    }
46}
47
48impl<E: Environment> AddAssign<Field<E>> for Field<E> {
49    /// Adds `other` to `self`.
50    #[inline]
51    fn add_assign(&mut self, other: Field<E>) {
52        self.field += other.field;
53    }
54}
55
56impl<E: Environment> AddAssign<&Field<E>> for Field<E> {
57    /// Adds `other` to `self`.
58    #[inline]
59    fn add_assign(&mut self, other: &Field<E>) {
60        self.field += other.field;
61    }
62}
63
64impl<E: Environment> Sub<Field<E>> for Field<E> {
65    type Output = Field<E>;
66
67    /// Returns the `difference` of `self` and `other`.
68    #[inline]
69    fn sub(self, other: Field<E>) -> Self::Output {
70        Field::new(self.field - other.field)
71    }
72}
73
74impl<E: Environment> Sub<&Field<E>> for Field<E> {
75    type Output = Field<E>;
76
77    /// Returns the `difference` of `self` and `other`.
78    #[inline]
79    fn sub(self, other: &Field<E>) -> Self::Output {
80        Field::new(self.field - other.field)
81    }
82}
83
84impl<E: Environment> SubAssign<Field<E>> for Field<E> {
85    /// Subtracts `other` from `self`.
86    #[inline]
87    fn sub_assign(&mut self, other: Field<E>) {
88        self.field -= other.field;
89    }
90}
91
92impl<E: Environment> SubAssign<&Field<E>> for Field<E> {
93    /// Subtracts `other` from `self`.
94    #[inline]
95    fn sub_assign(&mut self, other: &Field<E>) {
96        self.field -= other.field;
97    }
98}
99
100impl<E: Environment> Mul<Field<E>> for Field<E> {
101    type Output = Field<E>;
102
103    /// Returns the `product` of `self` and `other`.
104    #[inline]
105    fn mul(self, other: Field<E>) -> Self::Output {
106        Field::new(self.field * other.field)
107    }
108}
109
110impl<E: Environment> Mul<&Field<E>> for Field<E> {
111    type Output = Field<E>;
112
113    /// Returns the `product` of `self` and `other`.
114    #[inline]
115    fn mul(self, other: &Field<E>) -> Self::Output {
116        Field::new(self.field * other.field)
117    }
118}
119
120impl<E: Environment> MulAssign<Field<E>> for Field<E> {
121    /// Multiplies `self` by `other`.
122    #[inline]
123    fn mul_assign(&mut self, other: Field<E>) {
124        self.field *= other.field;
125    }
126}
127
128impl<E: Environment> MulAssign<&Field<E>> for Field<E> {
129    /// Multiplies `self` by `other`.
130    #[inline]
131    fn mul_assign(&mut self, other: &Field<E>) {
132        self.field *= other.field;
133    }
134}
135
136impl<E: Environment> Div<Field<E>> for Field<E> {
137    type Output = Field<E>;
138
139    /// Returns the `quotient` of `self` and `other`.
140    #[inline]
141    fn div(self, other: Field<E>) -> Self::Output {
142        match other.is_zero() {
143            true => E::halt(format!("Field division by zero: {self} / {other}")),
144            false => Field::new(self.field / other.field),
145        }
146    }
147}
148
149impl<E: Environment> Div<&Field<E>> for Field<E> {
150    type Output = Field<E>;
151
152    /// Returns the `quotient` of `self` and `other`.
153    #[inline]
154    fn div(self, other: &Field<E>) -> Self::Output {
155        match other.is_zero() {
156            true => E::halt(format!("Field division by zero: {self} / {other}")),
157            false => Field::new(self.field / other.field),
158        }
159    }
160}
161
162impl<E: Environment> DivAssign<Field<E>> for Field<E> {
163    /// Divides `self` by `other`.
164    #[inline]
165    fn div_assign(&mut self, other: Field<E>) {
166        match other.is_zero() {
167            true => E::halt(format!("Field division by zero: {self} / {other}")),
168            false => self.field /= other.field,
169        }
170    }
171}
172
173impl<E: Environment> DivAssign<&Field<E>> for Field<E> {
174    /// Divides `self` by `other`.
175    #[inline]
176    fn div_assign(&mut self, other: &Field<E>) {
177        match other.is_zero() {
178            true => E::halt(format!("Field division by zero: {self} / {other}")),
179            false => self.field /= other.field,
180        }
181    }
182}
183
184impl<E: Environment> Pow<Field<E>> for Field<E> {
185    type Output = Field<E>;
186
187    /// Returns the `power` of `self` to the power of `other`.
188    #[inline]
189    fn pow(self, other: Field<E>) -> Self::Output {
190        Field::new(self.field.pow(other.field.to_bigint()))
191    }
192}
193
194impl<E: Environment> Pow<&Field<E>> for Field<E> {
195    type Output = Field<E>;
196
197    /// Returns the `power` of `self` to the power of `other`.
198    #[inline]
199    fn pow(self, other: &Field<E>) -> Self::Output {
200        Field::new(self.field.pow(other.field.to_bigint()))
201    }
202}
203
204impl<E: Environment> Double for Field<E> {
205    type Output = Field<E>;
206
207    /// Returns the `double` of `self`.
208    #[inline]
209    fn double(&self) -> Self::Output {
210        Field::new(self.field.double())
211    }
212}
213
214impl<E: Environment> Inverse for Field<E> {
215    type Output = Field<E>;
216
217    /// Returns the `inverse` of `self`.
218    #[inline]
219    fn inverse(&self) -> Result<Self::Output> {
220        match self.field.inverse() {
221            Some(inverse) => Ok(Field::new(inverse)),
222            None => bail!("Failed to invert a field element: {self}"),
223        }
224    }
225}
226
227impl<E: Environment> Square for Field<E> {
228    type Output = Field<E>;
229
230    /// Returns the `square` of `self`.
231    #[inline]
232    fn square(&self) -> Self::Output {
233        Field::new(self.field.square())
234    }
235}
236
237impl<E: Environment> SquareRoot for Field<E> {
238    type Output = Field<E>;
239
240    /// Returns the `square_root` of `self`.
241    /// If there are two square roots, the bitwise lesser one is returned.
242    #[inline]
243    fn square_root(&self) -> Result<Self::Output> {
244        match self.field.sqrt() {
245            Some(sqrt) => {
246                // Return the smaller square root.
247                let sqrt = Field::new(sqrt);
248                let negative_sqrt: Field<E> = -sqrt;
249                match *(sqrt.is_less_than_or_equal(&negative_sqrt)) {
250                    true => Ok(sqrt),
251                    false => Ok(negative_sqrt),
252                }
253            }
254            None => bail!("Failed to square root a field element: {self}"),
255        }
256    }
257}
258
259impl<E: Environment> Field<E> {
260    /// Returns the `square_root` of `self`, where the least significant bit of the square root is zero.
261    #[inline]
262    pub fn even_square_root(&self) -> Result<Self> {
263        match self.field.sqrt() {
264            Some(sqrt) => {
265                let sqrt: Field<E> = Field::new(sqrt);
266                // Check the least significant bit of the square root.
267                // Note that the unwrap is safe since the number of bits is always greater than zero.
268                match *sqrt.to_bits_be().last().unwrap() {
269                    // If the lsb is set, return the negated square root.
270                    true => Ok(-sqrt),
271                    // Otherwise, return the square root.
272                    false => Ok(sqrt),
273                }
274            }
275            None => bail!("Failed to square root a field element: {self}"),
276        }
277    }
278}
279
280impl<E: Environment> Sum<Field<E>> for Field<E> {
281    /// Returns the `sum` of `self` and `other`.
282    #[inline]
283    fn sum<I: Iterator<Item = Field<E>>>(iter: I) -> Self {
284        iter.fold(Field::zero(), |a, b| a + b)
285    }
286}
287
288impl<'a, E: Environment> Sum<&'a Field<E>> for Field<E> {
289    /// Returns the `sum` of `self` and `other`.
290    #[inline]
291    fn sum<I: Iterator<Item = &'a Field<E>>>(iter: I) -> Self {
292        iter.fold(Field::zero(), |a, b| a + b)
293    }
294}
295
296impl<E: Environment> Product<Field<E>> for Field<E> {
297    /// Returns the `product` of `self` and `other`.
298    #[inline]
299    fn product<I: Iterator<Item = Field<E>>>(iter: I) -> Self {
300        iter.fold(Field::one(), |a, b| a * b)
301    }
302}
303
304impl<'a, E: Environment> Product<&'a Field<E>> for Field<E> {
305    /// Returns the `product` of `self` and `other`.
306    #[inline]
307    fn product<I: Iterator<Item = &'a Field<E>>>(iter: I) -> Self {
308        iter.fold(Field::one(), |a, b| a * b)
309    }
310}
311
312#[cfg(test)]
313mod tests {
314    use super::*;
315    use snarkvm_console_network_environment::Console;
316
317    type CurrentEnvironment = Console;
318
319    #[test]
320    fn test_div_by_zero_fails() {
321        let one = Field::<CurrentEnvironment>::one();
322        let zero = Field::<CurrentEnvironment>::zero();
323
324        let result = std::panic::catch_unwind(|| one / zero);
325        assert!(result.is_err()); // Probe further for specific error type here, if desired
326    }
327}