snarkvm_circuit_types_field/
inverse.rs1use super::*;
17
18impl<E: Environment> Inv for Field<E> {
19 type Output = Self;
20
21 fn inv(self) -> Self::Output {
22 Self::inverse(&self)
23 }
24}
25
26impl<E: Environment> Inv for &Field<E> {
27 type Output = Field<E>;
28
29 fn inv(self) -> Self::Output {
30 self.inverse()
31 }
32}
33
34impl<E: Environment> Inverse for Field<E> {
35 type Output = Field<E>;
36
37 fn inverse(&self) -> Self::Output {
38 let inverse = witness!(|self| match self.inverse() {
39 Ok(inverse) => inverse,
40 _ => console::Field::zero(),
41 });
42
43 E::enforce(|| (self, &inverse, E::one()));
45
46 inverse
47 }
48}
49
50impl<E: Environment> Metrics<dyn Inverse<Output = Field<E>>> for Field<E> {
51 type Case = Mode;
52
53 fn count(case: &Self::Case) -> Count {
54 match case.is_constant() {
55 true => Count::is(1, 0, 0, 0),
56 false => Count::is(0, 0, 1, 1),
57 }
58 }
59}
60
61impl<E: Environment> OutputMode<dyn Inverse<Output = Field<E>>> for Field<E> {
62 type Case = Mode;
63
64 fn output_mode(case: &Self::Case) -> Mode {
65 match case.is_constant() {
66 true => Mode::Constant,
67 false => Mode::Private,
68 }
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use snarkvm_circuit_environment::Circuit;
76
77 const ITERATIONS: u64 = 1_000;
78
79 fn check_inverse(name: &str, mode: Mode, rng: &mut TestRng) {
80 for _ in 0..ITERATIONS {
81 let given: console::Field<<Circuit as Environment>::Network> = Uniform::rand(rng);
83 if let Ok(expected) = given.inverse() {
85 let candidate = Field::<Circuit>::new(mode, given);
86
87 Circuit::scope(name, || {
88 let result = candidate.inverse();
89 assert_eq!(expected, result.eject_value());
90 assert_count!(Inverse(Field) => Field, &mode);
91 assert_output_mode!(Inverse(Field) => Field, &mode, result);
92 });
93 Circuit::reset();
94 }
95 }
96 }
97
98 #[test]
99 fn test_inverse() {
100 let mut rng = TestRng::default();
101
102 check_inverse("Constant", Mode::Constant, &mut rng);
103 check_inverse("Public", Mode::Public, &mut rng);
104 check_inverse("Private", Mode::Private, &mut rng);
105 }
106
107 #[test]
108 fn test_zero_inverse_fails() {
109 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
110
111 let result = std::panic::catch_unwind(|| Field::<Circuit>::zero().inverse());
112 assert!(result.is_err());
113 Circuit::reset();
114
115 let result = std::panic::catch_unwind(|| Field::<Circuit>::new(Mode::Constant, zero).inverse());
116 assert!(result.is_err());
117 Circuit::reset();
118
119 let candidate = Field::<Circuit>::new(Mode::Public, zero).inverse();
120 assert_eq!(zero, candidate.eject_value());
121 assert!(!Circuit::is_satisfied());
122 Circuit::reset();
123
124 let candidate = Field::<Circuit>::new(Mode::Private, zero).inverse();
125 assert_eq!(zero, candidate.eject_value());
126 assert!(!Circuit::is_satisfied());
127 Circuit::reset();
128 }
129}