snarkvm_console_types_scalar/
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 Scalar<E> {
19    type Output = Scalar<E>;
20
21    /// Returns the `negation` of `self`.
22    #[inline]
23    fn neg(self) -> Self::Output {
24        Scalar::new(-self.scalar)
25    }
26}
27
28impl<E: Environment> Add<Scalar<E>> for Scalar<E> {
29    type Output = Scalar<E>;
30
31    /// Returns the `sum` of `self` and `other`.
32    #[inline]
33    fn add(self, other: Scalar<E>) -> Self::Output {
34        Scalar::new(self.scalar + other.scalar)
35    }
36}
37
38impl<E: Environment> Add<&Scalar<E>> for Scalar<E> {
39    type Output = Scalar<E>;
40
41    /// Returns the `sum` of `self` and `other`.
42    #[inline]
43    fn add(self, other: &Scalar<E>) -> Self::Output {
44        Scalar::new(self.scalar + other.scalar)
45    }
46}
47
48impl<E: Environment> AddAssign<Scalar<E>> for Scalar<E> {
49    /// Adds `other` to `self`.
50    #[inline]
51    fn add_assign(&mut self, other: Scalar<E>) {
52        self.scalar += other.scalar;
53    }
54}
55
56impl<E: Environment> AddAssign<&Scalar<E>> for Scalar<E> {
57    /// Adds `other` to `self`.
58    #[inline]
59    fn add_assign(&mut self, other: &Scalar<E>) {
60        self.scalar += other.scalar;
61    }
62}
63
64impl<E: Environment> Sub<Scalar<E>> for Scalar<E> {
65    type Output = Scalar<E>;
66
67    /// Returns the `difference` of `self` and `other`.
68    #[inline]
69    fn sub(self, other: Scalar<E>) -> Self::Output {
70        Scalar::new(self.scalar - other.scalar)
71    }
72}
73
74impl<E: Environment> Sub<&Scalar<E>> for Scalar<E> {
75    type Output = Scalar<E>;
76
77    /// Returns the `difference` of `self` and `other`.
78    #[inline]
79    fn sub(self, other: &Scalar<E>) -> Self::Output {
80        Scalar::new(self.scalar - other.scalar)
81    }
82}
83
84impl<E: Environment> SubAssign<Scalar<E>> for Scalar<E> {
85    /// Subtracts `other` from `self`.
86    #[inline]
87    fn sub_assign(&mut self, other: Scalar<E>) {
88        self.scalar -= other.scalar;
89    }
90}
91
92impl<E: Environment> SubAssign<&Scalar<E>> for Scalar<E> {
93    /// Subtracts `other` from `self`.
94    #[inline]
95    fn sub_assign(&mut self, other: &Scalar<E>) {
96        self.scalar -= other.scalar;
97    }
98}
99
100impl<E: Environment> Mul<Scalar<E>> for Scalar<E> {
101    type Output = Scalar<E>;
102
103    /// Returns the `product` of `self` and `other`.
104    #[inline]
105    fn mul(self, other: Scalar<E>) -> Self::Output {
106        Scalar::new(self.scalar * other.scalar)
107    }
108}
109
110impl<E: Environment> Mul<&Scalar<E>> for Scalar<E> {
111    type Output = Scalar<E>;
112
113    /// Returns the `product` of `self` and `other`.
114    #[inline]
115    fn mul(self, other: &Scalar<E>) -> Self::Output {
116        Scalar::new(self.scalar * other.scalar)
117    }
118}
119
120impl<E: Environment> MulAssign<Scalar<E>> for Scalar<E> {
121    /// Multiplies `self` by `other`.
122    #[inline]
123    fn mul_assign(&mut self, other: Scalar<E>) {
124        self.scalar *= other.scalar;
125    }
126}
127
128impl<E: Environment> MulAssign<&Scalar<E>> for Scalar<E> {
129    /// Multiplies `self` by `other`.
130    #[inline]
131    fn mul_assign(&mut self, other: &Scalar<E>) {
132        self.scalar *= other.scalar;
133    }
134}
135
136impl<E: Environment> Div<Scalar<E>> for Scalar<E> {
137    type Output = Scalar<E>;
138
139    /// Returns the `quotient` of `self` and `other`.
140    #[inline]
141    fn div(self, other: Scalar<E>) -> Self::Output {
142        match other.is_zero() {
143            true => E::halt(format!("Scalar division by zero: {self} / {other}")),
144            false => Scalar::new(self.scalar / other.scalar),
145        }
146    }
147}
148
149impl<E: Environment> Div<&Scalar<E>> for Scalar<E> {
150    type Output = Scalar<E>;
151
152    /// Returns the `quotient` of `self` and `other`.
153    #[inline]
154    fn div(self, other: &Scalar<E>) -> Self::Output {
155        match other.is_zero() {
156            true => E::halt(format!("Scalar division by zero: {self} / {other}")),
157            false => Scalar::new(self.scalar / other.scalar),
158        }
159    }
160}
161
162impl<E: Environment> DivAssign<Scalar<E>> for Scalar<E> {
163    /// Divides `self` by `other`.
164    #[inline]
165    fn div_assign(&mut self, other: Scalar<E>) {
166        match other.is_zero() {
167            true => E::halt(format!("Scalar division by zero: {self} / {other}")),
168            false => self.scalar /= other.scalar,
169        }
170    }
171}
172
173impl<E: Environment> DivAssign<&Scalar<E>> for Scalar<E> {
174    /// Divides `self` by `other`.
175    #[inline]
176    fn div_assign(&mut self, other: &Scalar<E>) {
177        match other.is_zero() {
178            true => E::halt(format!("Scalar division by zero: {self} / {other}")),
179            false => self.scalar /= other.scalar,
180        }
181    }
182}
183
184impl<E: Environment> Pow<Scalar<E>> for Scalar<E> {
185    type Output = Scalar<E>;
186
187    /// Returns the `power` of `self` to the power of `other`.
188    #[inline]
189    fn pow(self, other: Scalar<E>) -> Self::Output {
190        Scalar::new(self.scalar.pow(other.scalar.to_bigint()))
191    }
192}
193
194impl<E: Environment> Pow<&Scalar<E>> for Scalar<E> {
195    type Output = Scalar<E>;
196
197    /// Returns the `power` of `self` to the power of `other`.
198    #[inline]
199    fn pow(self, other: &Scalar<E>) -> Self::Output {
200        Scalar::new(self.scalar.pow(other.scalar.to_bigint()))
201    }
202}
203
204impl<E: Environment> Double for Scalar<E> {
205    type Output = Scalar<E>;
206
207    /// Returns the `double` of `self`.
208    #[inline]
209    fn double(&self) -> Self::Output {
210        Scalar::new(self.scalar.double())
211    }
212}
213
214impl<E: Environment> Inverse for Scalar<E> {
215    type Output = Scalar<E>;
216
217    /// Returns the `inverse` of `self`.
218    #[inline]
219    fn inverse(&self) -> Result<Self::Output> {
220        match self.scalar.inverse() {
221            Some(inverse) => Ok(Scalar::new(inverse)),
222            None => bail!("Failed to invert a scalar element: {self}"),
223        }
224    }
225}
226
227impl<E: Environment> Square for Scalar<E> {
228    type Output = Scalar<E>;
229
230    /// Returns the `square` of `self`.
231    #[inline]
232    fn square(&self) -> Self::Output {
233        Scalar::new(self.scalar.square())
234    }
235}
236
237impl<E: Environment> Sum<Scalar<E>> for Scalar<E> {
238    /// Returns the `sum` of `self` and `other`.
239    #[inline]
240    fn sum<I: Iterator<Item = Scalar<E>>>(iter: I) -> Self {
241        iter.fold(Scalar::zero(), |a, b| a + b)
242    }
243}
244
245impl<'a, E: Environment> Sum<&'a Scalar<E>> for Scalar<E> {
246    /// Returns the `sum` of `self` and `other`.
247    #[inline]
248    fn sum<I: Iterator<Item = &'a Scalar<E>>>(iter: I) -> Self {
249        iter.fold(Scalar::zero(), |a, b| a + b)
250    }
251}
252
253impl<E: Environment> Product<Scalar<E>> for Scalar<E> {
254    /// Returns the `product` of `self` and `other`.
255    #[inline]
256    fn product<I: Iterator<Item = Scalar<E>>>(iter: I) -> Self {
257        iter.fold(Scalar::one(), |a, b| a * b)
258    }
259}
260
261impl<'a, E: Environment> Product<&'a Scalar<E>> for Scalar<E> {
262    /// Returns the `product` of `self` and `other`.
263    #[inline]
264    fn product<I: Iterator<Item = &'a Scalar<E>>>(iter: I) -> Self {
265        iter.fold(Scalar::one(), |a, b| a * b)
266    }
267}
268
269#[cfg(test)]
270mod tests {
271    use super::*;
272    use snarkvm_console_network_environment::Console;
273
274    type CurrentEnvironment = Console;
275
276    #[test]
277    fn test_div_by_zero_fails() {
278        let one = Scalar::<CurrentEnvironment>::one();
279        let zero = Scalar::<CurrentEnvironment>::zero();
280
281        let result = std::panic::catch_unwind(|| one / zero);
282        assert!(result.is_err()); // Probe further for specific error type here, if desired
283    }
284}