55//! the structure used in the main branch.
66
77use ark_ec::bn::BnConfig;
8- use ark_ff::{BitIteratorBE, Field};
8+ use ark_ff::{AdditiveGroup, BitIteratorBE, Field};
99use circuit_component_macro::component;
1010
11- use crate::{CircuitContext, gadgets::bn254::fq12::Fq12};
11+ use crate::{
12+ CircuitContext,
13+ circuit::TRUE_WIRE,
14+ gadgets::bn254::fq12::{Fq12, ValidFq12},
15+ };
1216
1317pub fn conjugate_native(f: ark_bn254::Fq12) -> ark_bn254::Fq12 {
1418 ark_bn254::Fq12::new(f.c0, -f.c1)
@@ -98,7 +102,16 @@ pub fn exp_by_neg_x_montgomery<C: CircuitContext>(circuit: &mut C, f: &Fq12) ->
98102}
99103
100104#[component]
101- pub fn final_exponentiation_montgomery<C: CircuitContext>(circuit: &mut C, f: &Fq12) -> Fq12 {
105+ pub fn final_exponentiation_montgomery<C: CircuitContext>(circuit: &mut C, f: &Fq12) -> ValidFq12 {
106+ let is_zero = Fq12::equal_constant(circuit, f, &ark_bn254::Fq12::ZERO);
107+ let is_valid = circuit.issue_wire();
108+ circuit.add_gate(crate::Gate {
109+ wire_a: is_zero,
110+ wire_b: TRUE_WIRE,
111+ wire_c: is_valid,
112+ gate_type: crate::GateType::Xor,
113+ });
114+
102115 let f_inv = Fq12::inverse_montgomery(circuit, f);
103116 let f_conjugate = Fq12::conjugate(circuit, f);
104117 let u = Fq12::mul_montgomery(circuit, &f_inv, &f_conjugate);
@@ -127,7 +140,9 @@ pub fn final_exponentiation_montgomery<C: CircuitContext>(circuit: &mut C, f: &F
127140 let y18 = Fq12::mul_montgomery(circuit, &r2, &y11);
128141 let y19 = Fq12::frobenius_montgomery(circuit, &y18, 3);
129142
130- Fq12::mul_montgomery(circuit, &y19, &y17)
143+ let f = Fq12::mul_montgomery(circuit, &y19, &y17);
144+
145+ ValidFq12 { f, is_valid }
131146}
132147
133148#[cfg(test)]
@@ -171,6 +186,7 @@ mod tests {
171186 }
172187 struct Out {
173188 value: ark_bn254::Fq12,
189+ valid: bool,
174190 }
175191 fn encode_fq6_to_wires<M: CircuitMode<WireValue = bool>>(
176192 val: &ark_bn254::Fq6,
@@ -260,7 +276,7 @@ mod tests {
260276 }
261277 }
262278 impl CircuitOutput<ExecuteMode> for Out {
263- type WireRepr = Fq12Wires ;
279+ type WireRepr = ValidFq12 ;
264280 fn decode(wires: Self::WireRepr, cache: &mut ExecuteMode) -> Self {
265281 fn decode_fq6_from_wires(
266282 wires: &Fq6Wires,
@@ -298,10 +314,12 @@ mod tests {
298314 ark_bn254::Fq2::new(ark_bn254::Fq::from(c2_c0), ark_bn254::Fq::from(c2_c1));
299315 ark_bn254::Fq6::new(c0, c1, c2)
300316 }
301- let c0 = decode_fq6_from_wires(&wires.0[0], cache);
302- let c1 = decode_fq6_from_wires(&wires.0[1], cache);
317+ let c0 = decode_fq6_from_wires(&wires.f.0[0], cache);
318+ let c1 = decode_fq6_from_wires(&wires.f.0[1], cache);
319+ let valid = cache.lookup_wire(wires.is_valid).expect("missing wire");
303320 Self {
304321 value: ark_bn254::Fq12::new(c0, c1),
322+ valid,
305323 }
306324 }
307325 }
@@ -312,6 +330,27 @@ mod tests {
312330 final_exponentiation_montgomery(ctx, &input.f)
313331 });
314332
315- assert_eq!(result.output_value.value, expected_m);
333+ assert!(
334+ result.output_value.valid,
335+ "final_exponentiation_montgomery input should be valid"
336+ );
337+ assert_eq!(
338+ result.output_value.value, expected_m,
339+ "final_exponentiation_montgomery output should be valid"
340+ );
341+
342+ // Test for non-invertible element
343+ let input = In {
344+ f: ark_bn254::Fq12::ZERO,
345+ };
346+ let result: StreamingResult<_, _, Out> =
347+ CircuitBuilder::streaming_execute(input, 10_000, |ctx, input| {
348+ final_exponentiation_montgomery(ctx, &input.f)
349+ });
350+
351+ assert!(
352+ !result.output_value.valid,
353+ "final_exponentiation_montgomery input should be invalid"
354+ );
316355 }
317356}
0 commit comments