snarkvm_circuit_types_field/
div.rs1use super::*;
17
18impl<E: Environment> Div<Field<E>> for Field<E> {
19 type Output = Field<E>;
20
21 fn div(self, other: Field<E>) -> Self::Output {
22 self / &other
23 }
24}
25
26impl<E: Environment> Div<&Field<E>> for Field<E> {
27 type Output = Field<E>;
28
29 fn div(self, other: &Field<E>) -> Self::Output {
30 &self / other
31 }
32}
33
34impl<E: Environment> Div<Field<E>> for &Field<E> {
35 type Output = Field<E>;
36
37 fn div(self, other: Field<E>) -> Self::Output {
38 self / &other
39 }
40}
41
42impl<E: Environment> Div<&Field<E>> for &Field<E> {
43 type Output = Field<E>;
44
45 fn div(self, other: &Field<E>) -> Self::Output {
46 let mut output = self.clone();
47 output /= other;
48 output
49 }
50}
51
52impl<E: Environment> DivAssign<Self> for Field<E> {
53 fn div_assign(&mut self, other: Self) {
54 *self /= &other;
55 }
56}
57
58impl<E: Environment> DivAssign<&Self> for Field<E> {
59 #[allow(clippy::suspicious_op_assign_impl)]
60 fn div_assign(&mut self, other: &Self) {
61 match other.is_constant() {
62 true if other.eject_value().is_zero() => E::halt("Attempted to divide by zero."),
64 _ => *self *= other.inverse(),
68 }
69 }
70}
71
72impl<E: Environment> Metrics<dyn Div<Field<E>, Output = Field<E>>> for Field<E> {
73 type Case = (Mode, Mode);
74
75 fn count(case: &Self::Case) -> Count {
76 match case {
77 (Mode::Constant, Mode::Constant) | (_, Mode::Constant) => Count::is(1, 0, 0, 0),
78 (Mode::Constant, _) => Count::is(0, 0, 1, 1),
79 (_, _) => Count::is(0, 0, 2, 2),
80 }
81 }
82}
83
84impl<E: Environment> OutputMode<dyn Div<Field<E>, Output = Field<E>>> for Field<E> {
85 type Case = (CircuitType<Field<E>>, CircuitType<Field<E>>);
86
87 fn output_mode(case: &Self::Case) -> Mode {
88 match (case.0.mode(), case.1.mode()) {
89 (Mode::Constant, Mode::Constant) => Mode::Constant,
90 (Mode::Public, Mode::Constant) => match &case.1 {
91 CircuitType::Constant(constant) => match constant.eject_value().is_one() {
92 true => Mode::Public,
93 false => Mode::Private,
94 },
95 _ => E::halt("The constant is required to determine the output mode of Public + Constant"),
96 },
97 (_, _) => Mode::Private,
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use snarkvm_circuit_environment::{Circuit, assert_count_fails};
106
107 const ITERATIONS: u64 = 1000;
108
109 fn check_div(
110 name: &str,
111 first: &console::Field<<Circuit as Environment>::Network>,
112 second: &console::Field<<Circuit as Environment>::Network>,
113 mode_a: Mode,
114 mode_b: Mode,
115 ) {
116 let a = &Field::<Circuit>::new(mode_a, *first);
117 let b = &Field::<Circuit>::new(mode_b, *second);
118
119 match second.is_zero() {
120 true => match mode_b.is_constant() {
121 true => {
122 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| Field::div(a.clone(), b)));
123 assert!(result.is_err());
124 }
125 false => {
126 Circuit::scope(name, || {
127 let _ = a / b;
128 assert_count_fails!(Div(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
129 });
130 }
131 },
132 false => {
133 let expected = *first / *second;
134 Circuit::scope(name, || {
135 let candidate = a / b;
136 assert_eq!(expected, candidate.eject_value(), "({} / {})", a.eject_value(), b.eject_value());
137 assert_count!(Div(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
138 assert_output_mode!(Div(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
139 });
140 }
141 }
142 }
143
144 fn check_div_assign(
145 name: &str,
146 first: &console::Field<<Circuit as Environment>::Network>,
147 second: &console::Field<<Circuit as Environment>::Network>,
148 mode_a: Mode,
149 mode_b: Mode,
150 ) {
151 let a = &Field::<Circuit>::new(mode_a, *first);
152 let b = &Field::<Circuit>::new(mode_b, *second);
153
154 match second.is_zero() {
155 true => match mode_b.is_constant() {
156 true => {
157 let result =
158 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| Field::div_assign(&mut a.clone(), b)));
159 assert!(result.is_err());
160 }
161 false => {
162 Circuit::scope(name, || {
163 let mut candidate = a.clone();
164 candidate /= b;
165 assert_count_fails!(Div(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
166 });
167 }
168 },
169 false => {
170 let expected = *first / *second;
171 Circuit::scope(name, || {
172 let mut candidate = a.clone();
173 candidate /= b;
174 assert_eq!(expected, candidate.eject_value(), "({} /= {})", a.eject_value(), b.eject_value());
175 assert_count!(Div(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
176 assert_output_mode!(Div(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
177 });
178 }
179 }
180 }
181
182 fn run_test(mode_a: Mode, mode_b: Mode) {
183 let mut rng = TestRng::default();
184
185 for i in 0..ITERATIONS {
186 let first = Uniform::rand(&mut rng);
187 let second = Uniform::rand(&mut rng);
188
189 let name = format!("Div: a / b {i}");
190 check_div(&name, &first, &second, mode_a, mode_b);
191 let name = format!("DivAssign: a / b {i}");
192 check_div_assign(&name, &first, &second, mode_a, mode_b);
193
194 let one = console::Field::<<Circuit as Environment>::Network>::one();
196 let name = format!("Div By One {i}");
197 check_div(&name, &first, &one, mode_a, mode_b);
198 let name = format!("DivAssign By One {i}");
199 check_div_assign(&name, &first, &one, mode_a, mode_b);
200
201 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
203 let name = format!("Div By Zero {i}");
204 check_div(&name, &first, &zero, mode_a, mode_b);
205 let name = format!("DivAssign By Zero {i}");
206 check_div_assign(&name, &first, &zero, mode_a, mode_b);
207 }
208 }
209
210 #[test]
211 fn test_constant_div_constant() {
212 run_test(Mode::Constant, Mode::Constant);
213 }
214
215 #[test]
216 fn test_constant_div_public() {
217 run_test(Mode::Constant, Mode::Public);
218 }
219
220 #[test]
221 fn test_constant_div_private() {
222 run_test(Mode::Constant, Mode::Private);
223 }
224
225 #[test]
226 fn test_public_div_constant() {
227 run_test(Mode::Public, Mode::Constant);
228 }
229
230 #[test]
231 fn test_public_div_public() {
232 run_test(Mode::Public, Mode::Public);
233 }
234
235 #[test]
236 fn test_public_div_private() {
237 run_test(Mode::Public, Mode::Private);
238 }
239
240 #[test]
241 fn test_private_div_constant() {
242 run_test(Mode::Private, Mode::Constant);
243 }
244
245 #[test]
246 fn test_private_div_public() {
247 run_test(Mode::Private, Mode::Public);
248 }
249
250 #[test]
251 fn test_private_div_private() {
252 run_test(Mode::Private, Mode::Private);
253 }
254
255 #[test]
256 fn test_div_by_zero_fails() {
257 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
258 let one = console::Field::<<Circuit as Environment>::Network>::one();
259
260 let result = std::panic::catch_unwind(|| Field::<Circuit>::one() / Field::zero());
261 assert!(result.is_err()); let result =
264 std::panic::catch_unwind(|| Field::<Circuit>::new(Mode::Constant, one) / Field::new(Mode::Constant, zero));
265 assert!(result.is_err()); Circuit::scope("Public Div by Zero", || {
268 let _ = Field::<Circuit>::new(Mode::Public, one) / Field::new(Mode::Public, zero);
269 assert!(!Circuit::is_satisfied_in_scope());
270 });
271
272 Circuit::scope("Private Div by Zero", || {
273 let _ = Field::<Circuit>::new(Mode::Private, one) / Field::new(Mode::Private, zero);
274 assert!(!Circuit::is_satisfied_in_scope());
275 });
276 }
277}