@@ -375,6 +375,35 @@ pub fn ell_circuit_evaluate(f: Wires, coeffs: (Wires, Wires, Wires), p: Wires) -
375375 ( circuit. 0 , n)
376376}
377377
378+ pub fn ell_by_constant_circuit ( f : Wires , coeffs : ( ark_bn254:: Fq2 , ark_bn254:: Fq2 , ark_bn254:: Fq2 ) , p : Wires ) -> Circuit {
379+ let mut circuit = Circuit :: empty ( ) ;
380+ let c0 = coeffs. 0 ;
381+ let c1 = coeffs. 1 ;
382+ let c2 = coeffs. 2 ;
383+
384+ let px = p[ 0 ..Fq :: N_BITS ] . to_vec ( ) ;
385+ let py = p[ Fq :: N_BITS ..2 * Fq :: N_BITS ] . to_vec ( ) ;
386+
387+ let new_c0 = circuit. extend ( Fq2 :: mul_constant_by_fq ( c0, py) ) ;
388+ let new_c1 = circuit. extend ( Fq2 :: mul_constant_by_fq ( c1, px) ) ;
389+ let new_f = circuit. extend ( Fq12 :: mul_by_034_constant4 ( f, new_c0, new_c1, c2) ) ;
390+
391+ circuit. add_wires ( new_f) ;
392+ circuit
393+ }
394+
395+ pub fn ell_by_constant_circuit_evaluate ( f : Wires , coeffs : ( ark_bn254:: Fq2 , ark_bn254:: Fq2 , ark_bn254:: Fq2 ) , p : Wires ) -> ( Wires , usize ) {
396+ let circuit = ell_by_constant_circuit ( f, coeffs, p) ;
397+
398+ let n = circuit. 1 . len ( ) ;
399+
400+ for mut gate in circuit. 1 {
401+ gate. evaluate ( ) ;
402+ }
403+
404+ ( circuit. 0 , n)
405+ }
406+
378407pub fn fq12_square_evaluate ( f : Wires ) -> ( Wires , usize ) {
379408 let circuit = Fq12 :: square ( f) ;
380409
@@ -560,6 +589,92 @@ pub fn multi_miller_loop_circuit_evaluate(ps: Vec<Wires>, qs: Vec<Wires>) -> (Wi
560589 ( f, gate_count)
561590}
562591
592+ pub fn multi_miller_loop_groth16_circuit_evaluate ( p1 : Wires , p2 : Wires , p3 : Wires , q1 : ark_bn254:: G2Affine , q2 : ark_bn254:: G2Affine , q3 : Wires ) -> ( Wires , usize ) {
593+ let mut gate_count = 0 ;
594+ let q1ell = ell_coeffs ( q1) ;
595+ let q2ell = ell_coeffs ( q2) ;
596+ let ( q3ell, gc) = ( ell_coeffs ( g2a_from_wires ( q3) ) . iter ( ) . map ( |( c0, c1, c2) | { ( wires_set_from_fq2 ( * c0) , wires_set_from_fq2 ( * c1) , wires_set_from_fq2 ( * c2) ) } ) . collect :: < Vec < _ > > ( ) , 4290000000 ) ; // ell_coeffs_circuit_evaluate(q3);
597+ gate_count += gc;
598+ let mut q1_ell = q1ell. iter ( ) ;
599+ let mut q2_ell = q2ell. iter ( ) ;
600+ let mut q3_ell = q3ell. iter ( ) ;
601+
602+ let mut f = wires_set_from_fq12 ( ark_bn254:: Fq12 :: ONE ) ;
603+
604+ for i in ( 1 ..ark_bn254:: Config :: ATE_LOOP_COUNT . len ( ) ) . rev ( ) {
605+ if i != ark_bn254:: Config :: ATE_LOOP_COUNT . len ( ) - 1 {
606+ let ( new_f, gc) = ( wires_set_from_fq12 ( fq12_from_wires ( f) . square ( ) ) , 70631715 ) ; // fq12_square_evaluate(f);
607+ f = new_f;
608+ gate_count += gc;
609+ }
610+
611+ let q1ell_next = q1_ell. next ( ) . unwrap ( ) ;
612+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q1ell_next, g1p_from_wires ( p1. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q1_ell.next().unwrap().clone(), p.clone());
613+ f = new_f;
614+ gate_count += gc;
615+
616+ let q2ell_next = q2_ell. next ( ) . unwrap ( ) ;
617+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q2ell_next, g1p_from_wires ( p2. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q2_ell.next().unwrap().clone(), p.clone());
618+ f = new_f;
619+ gate_count += gc;
620+
621+ let q3ell_next = q3_ell. next ( ) . unwrap ( ) . clone ( ) ;
622+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , ( fq2_from_wires ( q3ell_next. 0 ) , fq2_from_wires ( q3ell_next. 1 ) , fq2_from_wires ( q3ell_next. 2 ) ) , g1p_from_wires ( p3. clone ( ) ) ) ) , 67030677 ) ; // ell_circuit_evaluate(f, q3_ell.next().unwrap().clone(), p.clone());
623+ f = new_f;
624+ gate_count += gc;
625+
626+ let bit = ark_bn254:: Config :: ATE_LOOP_COUNT [ i - 1 ] ;
627+ if bit == 1 || bit == -1 {
628+ let q1ell_next = q1_ell. next ( ) . unwrap ( ) ;
629+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q1ell_next, g1p_from_wires ( p1. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q1_ell.next().unwrap().clone(), p.clone());
630+ f = new_f;
631+ gate_count += gc;
632+
633+ let q2ell_next = q2_ell. next ( ) . unwrap ( ) ;
634+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q2ell_next, g1p_from_wires ( p2. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q2_ell.next().unwrap().clone(), p.clone());
635+ f = new_f;
636+ gate_count += gc;
637+
638+ let q3ell_next = q3_ell. next ( ) . unwrap ( ) . clone ( ) ;
639+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , ( fq2_from_wires ( q3ell_next. 0 ) , fq2_from_wires ( q3ell_next. 1 ) , fq2_from_wires ( q3ell_next. 2 ) ) , g1p_from_wires ( p3. clone ( ) ) ) ) , 67030677 ) ; // ell_circuit_evaluate(f, q3_ell.next().unwrap().clone(), p.clone());
640+ f = new_f;
641+ gate_count += gc;
642+ }
643+ }
644+
645+ let q1ell_next = q1_ell. next ( ) . unwrap ( ) ;
646+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q1ell_next, g1p_from_wires ( p1. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q1_ell.next().unwrap().clone(), p.clone());
647+ f = new_f;
648+ gate_count += gc;
649+
650+ let q2ell_next = q2_ell. next ( ) . unwrap ( ) ;
651+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q2ell_next, g1p_from_wires ( p2. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q2_ell.next().unwrap().clone(), p.clone());
652+ f = new_f;
653+ gate_count += gc;
654+
655+ let q3ell_next = q3_ell. next ( ) . unwrap ( ) . clone ( ) ;
656+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , ( fq2_from_wires ( q3ell_next. 0 ) , fq2_from_wires ( q3ell_next. 1 ) , fq2_from_wires ( q3ell_next. 2 ) ) , g1p_from_wires ( p3. clone ( ) ) ) ) , 67030677 ) ; // ell_circuit_evaluate(f, q3_ell.next().unwrap().clone(), p.clone());
657+ f = new_f;
658+ gate_count += gc;
659+
660+ let q1ell_next = q1_ell. next ( ) . unwrap ( ) ;
661+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q1ell_next, g1p_from_wires ( p1. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q1_ell.next().unwrap().clone(), p.clone());
662+ f = new_f;
663+ gate_count += gc;
664+
665+ let q2ell_next = q2_ell. next ( ) . unwrap ( ) ;
666+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , * q2ell_next, g1p_from_wires ( p2. clone ( ) ) ) ) , 58977252 ) ; // ell_by_constant_circuit_evaluate(f, q2_ell.next().unwrap().clone(), p.clone());
667+ f = new_f;
668+ gate_count += gc;
669+
670+ let q3ell_next = q3_ell. next ( ) . unwrap ( ) . clone ( ) ;
671+ let ( new_f, gc) = ( wires_set_from_fq12 ( ell2 ( fq12_from_wires ( f) , ( fq2_from_wires ( q3ell_next. 0 ) , fq2_from_wires ( q3ell_next. 1 ) , fq2_from_wires ( q3ell_next. 2 ) ) , g1p_from_wires ( p3. clone ( ) ) ) ) , 67030677 ) ; // ell_circuit_evaluate(f, q3_ell.next().unwrap().clone(), p.clone());
672+ f = new_f;
673+ gate_count += gc;
674+
675+ ( f, gate_count)
676+ }
677+
563678#[ cfg( test) ]
564679mod tests {
565680 use std:: iter:: zip;
@@ -695,6 +810,23 @@ mod tests {
695810 assert_eq ! ( f, new_f) ;
696811 }
697812
813+ #[ test]
814+ fn test_ell_by_constant_circuit ( ) {
815+ let mut prng = ChaCha20Rng :: seed_from_u64 ( 0 ) ;
816+ let mut f = ark_bn254:: Fq12 :: rand ( & mut prng) ;
817+ let coeffs = ( ark_bn254:: Fq2 :: rand ( & mut prng) , ark_bn254:: Fq2 :: rand ( & mut prng) , ark_bn254:: Fq2 :: rand ( & mut prng) ) ;
818+ let p = ark_bn254:: G1Projective :: rand ( & mut prng) ;
819+
820+ let circuit = ell_by_constant_circuit ( wires_set_from_fq12 ( f) , coeffs, wires_set_from_g1p ( p) ) ;
821+ circuit. print_gate_type_counts ( ) ;
822+ for mut gate in circuit. 1 {
823+ gate. evaluate ( ) ;
824+ }
825+ let new_f = fq12_from_wires ( circuit. 0 ) ;
826+ ell ( & mut f, coeffs, p) ;
827+ assert_eq ! ( f, new_f) ;
828+ }
829+
698830 #[ test]
699831 fn test_miller_loop ( ) {
700832 let mut prng = ChaCha20Rng :: seed_from_u64 ( 0 ) ;
@@ -744,4 +876,21 @@ mod tests {
744876
745877 assert_eq ! ( fq12_from_wires( f) , expected_f) ;
746878 }
879+
880+ #[ test]
881+ fn test_multi_miller_loop_groth16_circuit_evaluate ( ) {
882+ let mut prng = ChaCha20Rng :: seed_from_u64 ( 0 ) ;
883+ let p1 = ark_bn254:: G1Projective :: rand ( & mut prng) ;
884+ let p2 = ark_bn254:: G1Projective :: rand ( & mut prng) ;
885+ let p3 = ark_bn254:: G1Projective :: rand ( & mut prng) ;
886+ let q1 = ark_bn254:: G2Affine :: rand ( & mut prng) ;
887+ let q2 = ark_bn254:: G2Affine :: rand ( & mut prng) ;
888+ let q3 = ark_bn254:: G2Affine :: rand ( & mut prng) ;
889+
890+ let expected_f = multi_miller_loop ( vec ! [ p1, p2, p3] , vec ! [ q1, q2, q3] ) ;
891+ let ( f, gate_count) = multi_miller_loop_groth16_circuit_evaluate ( wires_set_from_g1p ( p1) , wires_set_from_g1p ( p2) , wires_set_from_g1p ( p3) , q1, q2, wires_set_from_g2a ( q3) ) ;
892+ println ! ( "gate_count: {:?}" , gate_count) ;
893+
894+ assert_eq ! ( fq12_from_wires( f) , expected_f) ;
895+ }
747896}
0 commit comments