snarkvm_circuit_types_field/
pow.rs1use super::*;
17use snarkvm_circuit_environment::{Circuit, CircuitType};
18
19#[allow(clippy::only_used_in_recursion)]
20impl<E: Environment> Pow<Field<E>> for Field<E> {
21 type Output = Field<E>;
22
23 fn pow(self, exponent: Field<E>) -> Self::Output {
24 self.pow(&exponent)
25 }
26}
27
28impl<E: Environment> Pow<Field<E>> for &Field<E> {
29 type Output = Field<E>;
30
31 fn pow(self, exponent: Field<E>) -> Self::Output {
32 self.pow(&exponent)
33 }
34}
35
36#[allow(clippy::needless_borrow)]
37impl<E: Environment> Pow<&Field<E>> for Field<E> {
38 type Output = Field<E>;
39
40 fn pow(self, exponent: &Field<E>) -> Self::Output {
41 (&self).pow(exponent)
42 }
43}
44
45impl<E: Environment> Pow<&Field<E>> for &Field<E> {
46 type Output = Field<E>;
47
48 fn pow(self, exponent: &Field<E>) -> Self::Output {
49 let mut output = Field::one();
51
52 if exponent.is_constant() {
54 for bit in exponent.to_bits_be() {
55 output = output.square();
57 if bit.eject_value() {
59 output *= self;
60 }
61 }
62 }
63 else {
65 for bit in exponent.to_bits_be() {
66 output = output.square();
68 output = Field::ternary(&bit, &(&output * self), &output);
70 }
71 }
72
73 output
74 }
75}
76
77impl<E: Environment> Metrics<dyn Pow<Field<E>, Output = Field<E>>> for Field<E> {
78 type Case = (CircuitType<Field<E>>, CircuitType<Field<E>>);
79
80 fn count(case: &Self::Case) -> Count {
81 match (case.0.mode(), case.1.mode()) {
82 (Mode::Constant, Mode::Constant) => Count::is(253, 0, 0, 0),
83 (_, Mode::Constant) => match &case.1 {
84 CircuitType::Constant(constant) => {
85 let exponent_bits = constant.eject_value().to_bits_be();
87 let index = exponent_bits
88 .iter()
89 .position(|b| *b)
90 .unwrap_or(console::Field::<<Circuit as Environment>::Network>::size_in_bits() - 1);
91
92 let num_squares =
96 (console::Field::<<Circuit as Environment>::Network>::size_in_bits() - index - 1) as u64;
97 let num_multiplications = exponent_bits[index + 1..].iter().map(|bit| *bit as u64).sum::<u64>();
98
99 let num_private = num_squares + num_multiplications;
101 let num_constraints = num_private;
102 Count::is(253, 0, num_private, num_constraints)
103 }
104 _ => E::halt(format!(
105 "Constant is required to determine the `Count` for {} POW {}",
106 case.0.mode(),
107 case.1.mode()
108 )),
109 },
110 (Mode::Constant, _) => Count::is(0, 0, 1009, 1011),
111 (_, _) => Count::is(0, 0, 1262, 1264),
112 }
113 }
114}
115
116impl<E: Environment> OutputMode<dyn Pow<Field<E>, Output = Field<E>>> for Field<E> {
117 type Case = (CircuitType<Field<E>>, CircuitType<Field<E>>);
118
119 fn output_mode(case: &Self::Case) -> Mode {
120 match (case.0.mode(), case.1.mode()) {
121 (Mode::Constant, Mode::Constant) => Mode::Constant,
122 (mode_a, Mode::Constant) => match &case.1 {
123 CircuitType::Constant(constant) => match constant.eject_value() {
124 value if value.is_zero() => Mode::Constant,
125 value if value.is_one() => mode_a,
126 _ => Mode::Private,
127 },
128 _ => E::halt("The constant is required to determine the output mode of Public * Constant"),
129 },
130 (_, _) => Mode::Private,
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use snarkvm_circuit_environment::Circuit;
139
140 const ITERATIONS: u64 = 10;
141
142 fn check_pow(
143 name: &str,
144 expected: &console::Field<<Circuit as Environment>::Network>,
145 a: &Field<Circuit>,
146 b: &Field<Circuit>,
147 ) {
148 Circuit::scope(name, || {
149 let candidate = a.pow(b);
150 assert_eq!(*expected, candidate.eject_value(), "({}^{})", a.eject_value(), b.eject_value());
151 assert_count!(Pow(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)));
152 assert_output_mode!(Pow(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
153 });
154 }
155
156 fn run_test(mode_a: Mode, mode_b: Mode) {
157 let mut rng = TestRng::default();
158
159 for i in 0..ITERATIONS {
160 let first = Uniform::rand(&mut rng);
161 let second = Uniform::rand(&mut rng);
162
163 let a = Field::<Circuit>::new(mode_a, first);
164 let b = Field::<Circuit>::new(mode_b, second);
165
166 let expected = first.pow(second);
167
168 let name = format!("Pow: a ^ b {i}");
169 check_pow(&name, &expected, &a, &b);
170
171 let name = format!("Pow: a ^ 1 {i}");
173 let a = Field::<Circuit>::new(mode_a, first);
174 let one = Field::<Circuit>::new(mode_b, console::Field::<<Circuit as Environment>::Network>::one());
175 check_pow(&name, &first, &a, &one);
176
177 let name = format!("Pow: 1 ^ b {i}");
179 let one = Field::<Circuit>::new(mode_a, console::Field::<<Circuit as Environment>::Network>::one());
180 let b = Field::<Circuit>::new(mode_b, second);
181 check_pow(&name, &console::Field::<<Circuit as Environment>::Network>::one(), &one, &b);
182
183 let name = format!("Pow: a ^ 0 {i}");
185 let a = Field::<Circuit>::new(mode_a, first);
186 let zero = Field::<Circuit>::new(mode_b, console::Field::<<Circuit as Environment>::Network>::zero());
187 check_pow(&name, &console::Field::<<Circuit as Environment>::Network>::one(), &a, &zero);
188
189 let name = format!("Mul: 0 ^ b {i}");
191 let zero = Field::<Circuit>::new(mode_a, console::Field::<<Circuit as Environment>::Network>::zero());
192 let b = Field::<Circuit>::new(mode_b, second);
193 check_pow(&name, &console::Field::<<Circuit as Environment>::Network>::zero(), &zero, &b);
194 }
195
196 let zero = console::Field::<<Circuit as Environment>::Network>::zero();
197 let one = console::Field::<<Circuit as Environment>::Network>::one();
198
199 let name = "Mul: 0 ^ 0";
201 check_pow(name, &one, &Field::<Circuit>::new(mode_a, zero), &Field::<Circuit>::new(mode_b, zero));
202
203 let name = "Pow: 1 ^ 0";
205 check_pow(name, &one, &Field::<Circuit>::new(mode_a, one), &Field::<Circuit>::new(mode_b, zero));
206
207 let name = "Pow: 0 ^ 1";
209 check_pow(name, &zero, &Field::<Circuit>::new(mode_a, zero), &Field::<Circuit>::new(mode_b, one));
210
211 let name = "Pow: 1 ^ 1";
213 check_pow(name, &one, &Field::<Circuit>::new(mode_a, one), &Field::<Circuit>::new(mode_b, one));
214 }
215
216 #[test]
217 fn test_constant_pow_constant() {
218 run_test(Mode::Constant, Mode::Constant);
219 }
220
221 #[test]
222 fn test_constant_pow_public() {
223 run_test(Mode::Constant, Mode::Public);
224 }
225
226 #[test]
227 fn test_constant_pow_private() {
228 run_test(Mode::Constant, Mode::Private);
229 }
230
231 #[test]
232 fn test_public_pow_constant() {
233 run_test(Mode::Public, Mode::Constant);
234 }
235
236 #[test]
237 fn test_private_pow_constant() {
238 run_test(Mode::Private, Mode::Constant);
239 }
240
241 #[test]
242 fn test_public_pow_public() {
243 run_test(Mode::Public, Mode::Public);
244 }
245
246 #[test]
247 fn test_public_pow_private() {
248 run_test(Mode::Public, Mode::Private);
249 }
250
251 #[test]
252 fn test_private_pow_public() {
253 run_test(Mode::Private, Mode::Public);
254 }
255
256 #[test]
257 fn test_private_pow_private() {
258 run_test(Mode::Private, Mode::Private)
259 }
260}