@@ -149,6 +149,16 @@ pub fn frobenius_in_place(a: ark_bn254::Fq2, power: usize) -> ark_bn254::Fq2 {
149149 ark_bn254:: Fq2 :: new ( c0, c1)
150150}
151151
152+ pub fn frobenius_in_place_circuit ( a : Wires , power : usize ) -> Circuit {
153+ let mut circuit = Circuit :: empty ( ) ;
154+ let c0 = a[ 0 ..Fq :: N_BITS ] . to_vec ( ) ;
155+ let c1 = a[ Fq :: N_BITS ..2 * Fq :: N_BITS ] . to_vec ( ) ;
156+ let new_c1 = circuit. extend ( Fq :: mul_by_constant ( c1, ark_bn254:: Fq2Config :: FROBENIUS_COEFF_FP2_C1 [ power % 2 ] ) ) ;
157+ circuit. add_wires ( c0) ;
158+ circuit. add_wires ( new_c1) ;
159+ circuit
160+ }
161+
152162pub fn mul_by_char ( r : ark_bn254:: G2Affine ) -> ark_bn254:: G2Affine {
153163 let mut s = r;
154164 s. x = frobenius_in_place ( s. x , 1 ) ;
@@ -158,6 +168,20 @@ pub fn mul_by_char(r: ark_bn254::G2Affine) -> ark_bn254::G2Affine {
158168 s
159169}
160170
171+ pub fn mul_by_char_circuit ( r : Wires ) -> Circuit {
172+ let mut circuit = Circuit :: empty ( ) ;
173+ let r_x = r[ 0 ..Fq2 :: N_BITS ] . to_vec ( ) ;
174+ let r_y = r[ Fq2 :: N_BITS ..2 * Fq2 :: N_BITS ] . to_vec ( ) ;
175+
176+ let mut s_x = circuit. extend ( frobenius_in_place_circuit ( r_x, 1 ) ) ;
177+ s_x = circuit. extend ( Fq2 :: mul_by_constant ( s_x, ark_bn254:: Config :: TWIST_MUL_BY_Q_X . clone ( ) ) ) ;
178+ let mut s_y = circuit. extend ( frobenius_in_place_circuit ( r_y, 1 ) ) ;
179+ s_y = circuit. extend ( Fq2 :: mul_by_constant ( s_y, ark_bn254:: Config :: TWIST_MUL_BY_Q_Y . clone ( ) ) ) ;
180+ circuit. add_wires ( s_x) ;
181+ circuit. add_wires ( s_y) ;
182+ circuit
183+ }
184+
161185pub fn ell_coeffs ( q : ark_bn254:: G2Projective ) -> Vec < ( ark_bn254:: Fq2 , ark_bn254:: Fq2 , ark_bn254:: Fq2 ) > {
162186 let q_affine = q. into_affine ( ) ;
163187 let mut ellc = Vec :: new ( ) ;
@@ -283,6 +307,23 @@ mod tests {
283307 assert_eq ! ( r. z, new_r_z) ;
284308 }
285309
310+ #[ test]
311+ fn test_mul_by_char_circuit ( ) {
312+ let mut prng = ChaCha20Rng :: seed_from_u64 ( 0 ) ;
313+ let q = ark_bn254:: G2Affine :: rand ( & mut prng) ;
314+
315+ let circuit = mul_by_char_circuit ( wires_set_from_g2a ( q) ) ;
316+ circuit. print_gate_type_counts ( ) ;
317+ for mut gate in circuit. 1 {
318+ gate. evaluate ( ) ;
319+ }
320+ let c0 = fq2_from_wires ( circuit. 0 [ 0 ..Fq2 :: N_BITS ] . to_vec ( ) ) ;
321+ let c1 = fq2_from_wires ( circuit. 0 [ Fq2 :: N_BITS ..2 * Fq2 :: N_BITS ] . to_vec ( ) ) ;
322+ let coeffs = mul_by_char ( q) ;
323+ assert_eq ! ( c0, coeffs. x) ;
324+ assert_eq ! ( c1, coeffs. y) ;
325+ }
326+
286327 #[ test]
287328 fn test_miller_loop ( ) {
288329 let mut prng = ChaCha20Rng :: seed_from_u64 ( 0 ) ;
0 commit comments