snarkvm_console_types_integers/
bitwise.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, I: IntegerType> Equal for Integer<E, I> {
19    type Output = Boolean<E>;
20
21    /// Returns `true` if `self` and `other` are equal.
22    fn is_equal(&self, other: &Self) -> Self::Output {
23        Boolean::new(self == other)
24    }
25
26    /// Returns `true` if `self` and `other` are *not* equal.
27    fn is_not_equal(&self, other: &Self) -> Self::Output {
28        Boolean::new(self != other)
29    }
30}
31
32impl<E: Environment, I: IntegerType> Compare<Self> for Integer<E, I> {
33    type Output = Boolean<E>;
34
35    /// Returns `true` if `self` is less than `other`.
36    fn is_less_than(&self, other: &Self) -> Self::Output {
37        Boolean::new(self.integer < other.integer)
38    }
39
40    /// Returns `true` if `self` is greater than `other`.
41    fn is_greater_than(&self, other: &Self) -> Self::Output {
42        other.is_less_than(self)
43    }
44
45    /// Returns `true` if `self` is less than or equal to `other`.
46    fn is_less_than_or_equal(&self, other: &Self) -> Self::Output {
47        other.is_greater_than_or_equal(self)
48    }
49
50    /// Returns `true` if `self` is greater than or equal to `other`.
51    fn is_greater_than_or_equal(&self, other: &Self) -> Self::Output {
52        !self.is_less_than(other)
53    }
54}
55
56impl<E: Environment, I: IntegerType> Not for Integer<E, I> {
57    type Output = Self;
58
59    /// Returns the bitwise `NOT` of `self`.
60    #[inline]
61    fn not(self) -> Self::Output {
62        Integer::new(self.integer.not())
63    }
64}
65
66impl<E: Environment, I: IntegerType> BitAnd for Integer<E, I> {
67    type Output = Self;
68
69    /// Returns the bitwise `AND` of `self` and `other`.
70    #[inline]
71    fn bitand(self, other: Self) -> Self::Output {
72        Integer::new(self.integer & other.integer)
73    }
74}
75
76impl<E: Environment, I: IntegerType> BitAnd<&Integer<E, I>> for Integer<E, I> {
77    type Output = Self;
78
79    /// Returns the bitwise `AND` of `self` and `other`.
80    #[inline]
81    fn bitand(self, other: &Integer<E, I>) -> Self::Output {
82        Integer::new(self.integer & other.integer)
83    }
84}
85
86impl<E: Environment, I: IntegerType> BitAndAssign for Integer<E, I> {
87    /// Performs the bitwise `AND` of `self` and `other` and assigns the result to `self`.
88    #[inline]
89    fn bitand_assign(&mut self, other: Self) {
90        self.integer = self.integer & other.integer;
91    }
92}
93
94impl<E: Environment, I: IntegerType> BitOr for Integer<E, I> {
95    type Output = Self;
96
97    /// Returns the bitwise `OR` of `self` and `other`.
98    #[inline]
99    fn bitor(self, other: Self) -> Self::Output {
100        Integer::new(self.integer | other.integer)
101    }
102}
103
104impl<E: Environment, I: IntegerType> BitOr<&Integer<E, I>> for Integer<E, I> {
105    type Output = Self;
106
107    /// Returns the bitwise `OR` of `self` and `other`.
108    #[inline]
109    fn bitor(self, other: &Integer<E, I>) -> Self::Output {
110        Integer::new(self.integer | other.integer)
111    }
112}
113
114impl<E: Environment, I: IntegerType> BitOrAssign for Integer<E, I> {
115    /// Performs the bitwise `OR` of `self` and `other` and assigns the result to `self`.
116    #[inline]
117    fn bitor_assign(&mut self, other: Self) {
118        self.integer = self.integer | other.integer;
119    }
120}
121
122impl<E: Environment, I: IntegerType> BitXor for Integer<E, I> {
123    type Output = Self;
124
125    /// Returns the bitwise `XOR` of `self` and `other`.
126    #[inline]
127    fn bitxor(self, other: Self) -> Self::Output {
128        Integer::new(self.integer ^ other.integer)
129    }
130}
131
132impl<E: Environment, I: IntegerType> BitXor<&Integer<E, I>> for Integer<E, I> {
133    type Output = Self;
134
135    /// Returns the bitwise `XOR` of `self` and `other`.
136    #[inline]
137    fn bitxor(self, other: &Integer<E, I>) -> Self::Output {
138        Integer::new(self.integer ^ other.integer)
139    }
140}
141
142impl<E: Environment, I: IntegerType> BitXorAssign for Integer<E, I> {
143    /// Performs the bitwise `XOR` of `self` and `other` and assigns the result to `self`.
144    #[inline]
145    fn bitxor_assign(&mut self, other: Self) {
146        self.integer = self.integer ^ other.integer;
147    }
148}
149
150impl<E: Environment, I: IntegerType, M: Magnitude> Shl<Integer<E, M>> for Integer<E, I> {
151    type Output = Self;
152
153    /// Shifts `self` to the left by `n` bits.
154    #[inline]
155    fn shl(self, n: Integer<E, M>) -> Self::Output {
156        // Unwrap is safe as we only cast up.
157        match self.integer.checked_shl(&n.integer.to_u32().unwrap()) {
158            Some(shifted) => Integer::new(shifted),
159            None => E::halt(format!("Failed to shift {self} left by {n} bits")),
160        }
161    }
162}
163
164impl<E: Environment, I: IntegerType, M: Magnitude> Shl<&Integer<E, M>> for Integer<E, I> {
165    type Output = Self;
166
167    /// Shifts `self` to the left by `n` bits.
168    #[inline]
169    fn shl(self, n: &Integer<E, M>) -> Self::Output {
170        // Unwrap is safe as we only cast up.
171        match self.integer.checked_shl(&n.integer.to_u32().unwrap()) {
172            Some(shifted) => Integer::new(shifted),
173            None => E::halt(format!("Failed to shift {self} left by {n} bits")),
174        }
175    }
176}
177
178impl<E: Environment, I: IntegerType, M: Magnitude> ShlChecked<Integer<E, M>> for Integer<E, I> {
179    type Output = Self;
180
181    /// Shifts `self` to the left by `n` bits.
182    #[inline]
183    fn shl_checked(&self, n: &Integer<E, M>) -> Self::Output {
184        // Unwrap is safe as we only cast up.
185        match self.integer.checked_shl(&n.integer.to_u32().unwrap()) {
186            Some(shifted) => Integer::new(shifted),
187            None => E::halt(format!("Failed to shift {self} left by {n} bits")),
188        }
189    }
190}
191
192impl<E: Environment, I: IntegerType, M: Magnitude> ShlWrapped<Integer<E, M>> for Integer<E, I> {
193    type Output = Self;
194
195    /// Shifts `self` to the left by `n` bits, continuing past the boundary.
196    #[inline]
197    fn shl_wrapped(&self, n: &Integer<E, M>) -> Self::Output {
198        Integer::new(self.integer.wrapping_shl(n.integer.to_u32().unwrap()))
199    }
200}
201
202impl<E: Environment, I: IntegerType, M: Magnitude> ShlAssign<Integer<E, M>> for Integer<E, I> {
203    /// Shifts `self` to the left by `n` bits and assigns the result to `self`.
204    #[inline]
205    fn shl_assign(&mut self, n: Integer<E, M>) {
206        match self.integer.checked_shl(&n.integer.to_u32().unwrap()) {
207            // Unwrap is safe as we only cast up.
208            Some(shifted) => {
209                self.integer = shifted;
210            }
211            None => E::halt(format!("Failed to shift {self} left by {n} bits")),
212        }
213    }
214}
215
216impl<E: Environment, I: IntegerType, M: Magnitude> Shr<Integer<E, M>> for Integer<E, I> {
217    type Output = Self;
218
219    /// Shifts `self` to the right by `n` bits.
220    #[inline]
221    fn shr(self, n: Integer<E, M>) -> Self::Output {
222        match self.integer.checked_shr(n.integer.to_u32().unwrap()) {
223            // Unwrap is safe as we only cast up.
224            Some(shifted) => Integer::new(shifted),
225            None => E::halt(format!("Failed to shift {self} right by {n} bits")),
226        }
227    }
228}
229
230impl<E: Environment, I: IntegerType, M: Magnitude> Shr<&Integer<E, M>> for Integer<E, I> {
231    type Output = Self;
232
233    /// Shifts `self` to the right by `n` bits.
234    #[inline]
235    fn shr(self, n: &Integer<E, M>) -> Self::Output {
236        match self.integer.checked_shr(n.integer.to_u32().unwrap()) {
237            // Unwrap is safe as we only cast up.
238            Some(shifted) => Integer::new(shifted),
239            None => E::halt(format!("Failed to shift {self} right by {n} bits")),
240        }
241    }
242}
243
244impl<E: Environment, I: IntegerType, M: Magnitude> ShrChecked<Integer<E, M>> for Integer<E, I> {
245    type Output = Self;
246
247    /// Shifts `self` to the right by `n` bits.
248    #[inline]
249    fn shr_checked(&self, n: &Integer<E, M>) -> Self::Output {
250        match self.integer.checked_shr(n.integer.to_u32().unwrap()) {
251            Some(shifted) => Integer::new(shifted),
252            None => E::halt(format!("Failed to shift {self} right by {n} bits")),
253        }
254    }
255}
256
257impl<E: Environment, I: IntegerType, M: Magnitude> ShrWrapped<Integer<E, M>> for Integer<E, I> {
258    type Output = Self;
259
260    /// Shifts `self` to the right by `n` bits, continuing past the boundary.
261    #[inline]
262    fn shr_wrapped(&self, n: &Integer<E, M>) -> Self::Output {
263        Integer::new(self.integer.wrapping_shr(n.integer.to_u32().unwrap()))
264    }
265}
266
267impl<E: Environment, I: IntegerType, M: Magnitude> ShrAssign<Integer<E, M>> for Integer<E, I> {
268    /// Shifts `self` to the right by `n` bits and assigns the result to `self`.
269    #[inline]
270    fn shr_assign(&mut self, n: Integer<E, M>) {
271        match self.integer.checked_shr(n.integer.to_u32().unwrap()) {
272            // Unwrap is safe as we only cast up.
273            Some(shifted) => {
274                self.integer = shifted;
275            }
276            None => E::halt(format!("Failed to shift {self} right by {n} bits")),
277        }
278    }
279}
280
281impl<E: Environment, I: IntegerType> Ternary for Integer<E, I> {
282    type Boolean = Boolean<E>;
283    type Output = Self;
284
285    /// Returns `first` if `condition` is `true`, otherwise returns `second`.
286    fn ternary(condition: &Self::Boolean, first: &Self, second: &Self) -> Self::Output {
287        match **condition {
288            true => *first,
289            false => *second,
290        }
291    }
292}