snarkvm_circuit_types_field/
mul.rs

1// Copyright (c) 2019-2025 Provable Inc.
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> 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                // Ensure self * other == product.
69                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            // Test identity.
182            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            // Test zero.
195            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        // Sample two random elements.
259        let a = Uniform::rand(&mut rng);
260        let b = Uniform::rand(&mut rng);
261        let expected = a * b;
262
263        // Constant
264        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        // Private
270        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}