1use super::*;
17
18impl<E: Environment> Mul<Field<E>> for Field<E> {
19 type Output = Field<E>;
20
21 fn mul(self, other: Field<E>) -> Self::Output {
22 self * &other
23 }
24}
25
26impl<E: Environment> Mul<&Field<E>> for Field<E> {
27 type Output = Field<E>;
28
29 fn mul(self, other: &Field<E>) -> Self::Output {
30 let mut output = self;
31 output *= other;
32 output
33 }
34}
35
36impl<E: Environment> Mul<Field<E>> for &Field<E> {
37 type Output = Field<E>;
38
39 fn mul(self, other: Field<E>) -> Self::Output {
40 other * self
41 }
42}
43
44impl<E: Environment> Mul<&Field<E>> for &Field<E> {
45 type Output = Field<E>;
46
47 fn mul(self, other: &Field<E>) -> Self::Output {
48 let mut output = self.clone();
49 output *= other;
50 output
51 }
52}
53
54impl<E: Environment> MulAssign<Field<E>> for Field<E> {
55 fn mul_assign(&mut self, other: Field<E>) {
56 *self *= &other;
57 }
58}
59
60impl<E: Environment> MulAssign<&Field<E>> for Field<E> {
61 fn mul_assign(&mut self, other: &Field<E>) {
62 match (self.is_constant(), other.is_constant()) {
63 (true, true) | (false, true) => *self = (&self.linear_combination * *other.eject_value()).into(),
64 (true, false) => *self = (&other.linear_combination * *self.eject_value()).into(),
65 (false, false) => {
66 let product = witness!(|self, other| self * other);
67
68 E::enforce(|| (&*self, other, &product));
70
71 *self = product;
72 }
73 }
74 }
75}
76
77impl<E: Environment> Metrics<dyn Mul<Field<E>, Output = Field<E>>> for Field<E> {
78 type Case = (Mode, Mode);
79
80 fn count(case: &Self::Case) -> Count {
81 match case.0.is_constant() || case.1.is_constant() {
82 true => Count::is(0, 0, 0, 0),
83 false => Count::is(0, 0, 1, 1),
84 }
85 }
86}
87
88impl<E: Environment> OutputMode<dyn Mul<Field<E>, Output = Field<E>>> for Field<E> {
89 type Case = (CircuitType<Field<E>>, CircuitType<Field<E>>);
90
91 fn output_mode(case: &Self::Case) -> Mode {
92 match (case.0.mode(), case.1.mode()) {
93 (Mode::Constant, Mode::Constant) => Mode::Constant,
94 (Mode::Constant, Mode::Public) => match &case.0 {
95 CircuitType::Constant(constant) => match constant.eject_value() {
96 value if value.is_zero() => Mode::Constant,
97 value if value.is_one() => Mode::Public,
98 _ => Mode::Private,
99 },
100 _ => E::halt("The constant is required to determine the output mode of Constant * Public"),
101 },
102 (Mode::Public, Mode::Constant) => match &case.1 {
103 CircuitType::Constant(constant) => match constant.eject_value() {
104 value if value.is_zero() => Mode::Constant,
105 value if value.is_one() => Mode::Public,
106 _ => Mode::Private,
107 },
108 _ => E::halt("The constant is required to determine the output mode of Public * Constant"),
109 },
110 (Mode::Private, Mode::Constant) => match &case.1 {
111 CircuitType::Constant(constant) => match constant.eject_value() {
112 value if value.is_zero() => Mode::Constant,
113 _ => Mode::Private,
114 },
115 _ => E::halt("The constant is required to determine the output mode of Private * Constant"),
116 },
117 (Mode::Constant, Mode::Private) => match &case.0 {
118 CircuitType::Constant(constant) => match constant.eject_value() {
119 value if value.is_zero() => Mode::Constant,
120 _ => Mode::Private,
121 },
122 _ => E::halt("The constant is required to determine the output mode of Constant * Private"),
123 },
124 (_, _) => Mode::Private,
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use snarkvm_circuit_environment::Circuit;
133
134 const ITERATIONS: u64 = 100;
135
136 fn check_mul(
137 name: &str,
138 expected: &console::Field<<Circuit as Environment>::Network>,
139 a: &Field<Circuit>,
140 b: &Field<Circuit>,
141 ) {
142 Circuit::scope(name, || {
143 let candidate = a * b;
144 assert_eq!(*expected, candidate.eject_value(), "({} * {})", a.eject_value(), b.eject_value());
145 assert_count!(Mul(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
146 assert_output_mode!(Mul(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
147 });
148 }
149
150 fn check_mul_assign(
151 name: &str,
152 expected: &console::Field<<Circuit as Environment>::Network>,
153 a: &Field<Circuit>,
154 b: &Field<Circuit>,
155 ) {
156 Circuit::scope(name, || {
157 let mut candidate = a.clone();
158 candidate *= b;
159 assert_eq!(*expected, candidate.eject_value(), "({} * {})", a.eject_value(), b.eject_value());
160 assert_count!(Mul(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
161 assert_output_mode!(Mul(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
162 });
163 }
164
165 fn run_test(mode_a: Mode, mode_b: Mode) {
166 let mut rng = TestRng::default();
167
168 for i in 0..ITERATIONS {
169 let first = Uniform::rand(&mut rng);
170 let second = Uniform::rand(&mut rng);
171
172 let expected = first * second;
173 let a = Field::<Circuit>::new(mode_a, first);
174 let b = Field::<Circuit>::new(mode_b, second);
175
176 let name = format!("Mul: a + b {i}");
177 check_mul(&name, &expected, &a, &b);
178 let name = format!("MulAssign: a + b {i}");
179 check_mul_assign(&name, &expected, &a, &b);
180
181 let name = format!("Mul: a * 1 {i}");
183 let one = Field::<Circuit>::new(mode_b, console::Field::<<Circuit as Environment>::Network>::one());
184 check_mul(&name, &first, &a, &one);
185 let name = format!("MulAssign: a * 1 {i}");
186 check_mul_assign(&name, &first, &a, &one);
187
188 let name = format!("Mul: 1 * b {i}");
189 let one = Field::<Circuit>::new(mode_a, console::Field::<<Circuit as Environment>::Network>::one());
190 check_mul(&name, &second, &one, &b);
191 let name = format!("MulAssign: 1 * b {i}");
192 check_mul_assign(&name, &second, &one, &b);
193
194 let name = format!("Mul: a * 0 {i}");
196 let zero = Field::<Circuit>::new(mode_b, console::Field::<<Circuit as Environment>::Network>::zero());
197 check_mul(&name, &console::Field::<<Circuit as Environment>::Network>::zero(), &a, &zero);
198 let name = format!("MulAssign: a * 0 {i}");
199 check_mul_assign(&name, &console::Field::<<Circuit as Environment>::Network>::zero(), &a, &zero);
200
201 let name = format!("Mul: 0 * b {i}");
202 let zero = Field::<Circuit>::new(mode_a, console::Field::<<Circuit as Environment>::Network>::zero());
203 check_mul(&name, &console::Field::<<Circuit as Environment>::Network>::zero(), &zero, &b);
204 let name = format!("MulAssign: 0 * b {i}");
205 check_mul_assign(&name, &console::Field::<<Circuit as Environment>::Network>::zero(), &zero, &b);
206 }
207 }
208
209 #[test]
210 fn test_constant_times_constant() {
211 run_test(Mode::Constant, Mode::Constant);
212 }
213
214 #[test]
215 fn test_constant_times_public() {
216 run_test(Mode::Constant, Mode::Public);
217 }
218
219 #[test]
220 fn test_constant_times_private() {
221 run_test(Mode::Constant, Mode::Private);
222 }
223
224 #[test]
225 fn test_public_times_constant() {
226 run_test(Mode::Public, Mode::Constant);
227 }
228
229 #[test]
230 fn test_private_times_constant() {
231 run_test(Mode::Private, Mode::Constant);
232 }
233
234 #[test]
235 fn test_public_times_public() {
236 run_test(Mode::Public, Mode::Public);
237 }
238
239 #[test]
240 fn test_public_times_private() {
241 run_test(Mode::Public, Mode::Private);
242 }
243
244 #[test]
245 fn test_private_times_public() {
246 run_test(Mode::Private, Mode::Public);
247 }
248
249 #[test]
250 fn test_private_times_private() {
251 run_test(Mode::Private, Mode::Private);
252 }
253
254 #[test]
255 fn test_mul_matches() {
256 let mut rng = TestRng::default();
257
258 let a = Uniform::rand(&mut rng);
260 let b = Uniform::rand(&mut rng);
261 let expected = a * b;
262
263 let first = Field::<Circuit>::new(Mode::Constant, a);
265 let second = Field::<Circuit>::new(Mode::Constant, b);
266 let candidate_a = first * second;
267 assert_eq!(expected, candidate_a.eject_value());
268
269 let first = Field::<Circuit>::new(Mode::Private, a);
271 let second = Field::<Circuit>::new(Mode::Private, b);
272 let candidate_b = first * second;
273 assert_eq!(expected, candidate_b.eject_value());
274 }
275
276 #[test]
277 fn test_0_times_0() {
278 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
279
280 let candidate = Field::<Circuit>::zero() * Field::zero();
281 assert_eq!(zero, candidate.eject_value());
282
283 let candidate = Field::<Circuit>::zero() * &Field::zero();
284 assert_eq!(zero, candidate.eject_value());
285
286 let candidate = Field::<Circuit>::new(Mode::Public, zero) * Field::new(Mode::Public, zero);
287 assert_eq!(zero, candidate.eject_value());
288
289 let candidate = Field::<Circuit>::new(Mode::Public, zero) * Field::new(Mode::Private, zero);
290 assert_eq!(zero, candidate.eject_value());
291
292 let candidate = Field::<Circuit>::new(Mode::Private, zero) * Field::new(Mode::Private, zero);
293 assert_eq!(zero, candidate.eject_value());
294 }
295
296 #[test]
297 fn test_0_times_1() {
298 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
299 let one = console::Field::<<Circuit as Environment>::Network>::one();
300
301 let candidate = Field::<Circuit>::zero() * Field::one();
302 assert_eq!(zero, candidate.eject_value());
303
304 let candidate = Field::<Circuit>::zero() * &Field::one();
305 assert_eq!(zero, candidate.eject_value());
306
307 let candidate = Field::<Circuit>::one() * Field::zero();
308 assert_eq!(zero, candidate.eject_value());
309
310 let candidate = Field::<Circuit>::one() * &Field::zero();
311 assert_eq!(zero, candidate.eject_value());
312
313 let candidate = Field::<Circuit>::new(Mode::Public, one) * Field::new(Mode::Public, zero);
314 assert_eq!(zero, candidate.eject_value());
315
316 let candidate = Field::<Circuit>::new(Mode::Public, one) * Field::new(Mode::Private, zero);
317 assert_eq!(zero, candidate.eject_value());
318
319 let candidate = Field::<Circuit>::new(Mode::Private, one) * Field::new(Mode::Private, zero);
320 assert_eq!(zero, candidate.eject_value());
321 }
322
323 #[test]
324 fn test_1_times_1() {
325 let one = console::Field::<<Circuit as Environment>::Network>::one();
326
327 let candidate = Field::<Circuit>::one() * Field::one();
328 assert_eq!(one, candidate.eject_value());
329
330 let candidate = Field::<Circuit>::one() * &Field::one();
331 assert_eq!(one, candidate.eject_value());
332
333 let candidate = Field::<Circuit>::new(Mode::Public, one) * Field::new(Mode::Public, one);
334 assert_eq!(one, candidate.eject_value());
335
336 let candidate = Field::<Circuit>::new(Mode::Private, one) * Field::new(Mode::Public, one);
337 assert_eq!(one, candidate.eject_value());
338
339 let candidate = Field::<Circuit>::new(Mode::Private, one) * Field::new(Mode::Private, one);
340 assert_eq!(one, candidate.eject_value());
341 }
342
343 #[test]
344 fn test_2_times_2() {
345 let one = console::Field::<<Circuit as Environment>::Network>::one();
346 let two = one + one;
347 let four = two + two;
348
349 let candidate_two = Field::<Circuit>::one() + Field::one();
350 let candidate = candidate_two * (Field::<Circuit>::one() + Field::one());
351 assert_eq!(four, candidate.eject_value());
352
353 let candidate = Field::<Circuit>::new(Mode::Public, two) * Field::new(Mode::Public, two);
354 assert_eq!(four, candidate.eject_value());
355
356 let candidate = Field::<Circuit>::new(Mode::Private, two) * Field::new(Mode::Public, two);
357 assert_eq!(four, candidate.eject_value());
358
359 let candidate = Field::<Circuit>::new(Mode::Private, two) * Field::new(Mode::Private, two);
360 assert_eq!(four, candidate.eject_value());
361 }
362}