@@ -158,6 +158,7 @@ fn ethereum_builtin(name: &str) -> Box<Impl> {
158
158
"modexp" => Box :: new ( ModexpImpl ) as Box < Impl > ,
159
159
"bn128_add" => Box :: new ( Bn128AddImpl ) as Box < Impl > ,
160
160
"bn128_mul" => Box :: new ( Bn128MulImpl ) as Box < Impl > ,
161
+ "bn128_pairing" => Box :: new ( Bn128PairingImpl ) as Box < Impl > ,
161
162
_ => panic ! ( "invalid builtin name: {}" , name) ,
162
163
}
163
164
}
@@ -191,6 +192,9 @@ struct Bn128AddImpl;
191
192
#[ derive( Debug ) ]
192
193
struct Bn128MulImpl ;
193
194
195
+ #[ derive( Debug ) ]
196
+ struct Bn128PairingImpl ;
197
+
194
198
impl Impl for Identity {
195
199
fn execute ( & self , input : & [ u8 ] , output : & mut BytesRef ) -> Result < ( ) , Error > {
196
200
output. write ( 0 , input) ;
@@ -393,11 +397,109 @@ impl Impl for Bn128MulImpl {
393
397
}
394
398
}
395
399
400
+ mod bn128_gen {
401
+ use bn:: { AffineG1 , AffineG2 , Fq , Fq2 , G1 , G2 , Gt , pairing} ;
402
+
403
+ lazy_static ! {
404
+ pub static ref P1 : G1 = G1 :: from( AffineG1 :: new(
405
+ Fq :: from_str( "1" ) . expect( "1 is a valid field element" ) ,
406
+ Fq :: from_str( "2" ) . expect( "2 is a valid field element" ) ,
407
+ ) . expect( "Generator P1(1, 2) is a valid curve point" ) ) ;
408
+ }
409
+
410
+ lazy_static ! {
411
+ pub static ref P2 : G2 = G2 :: from( AffineG2 :: new(
412
+ Fq2 :: new(
413
+ Fq :: from_str( "10857046999023057135944570762232829481370756359578518086990519993285655852781" )
414
+ . expect( "a valid field element" ) ,
415
+ Fq :: from_str( "11559732032986387107991004021392285783925812861821192530917403151452391805634" )
416
+ . expect( "a valid field element" ) ,
417
+ ) ,
418
+ Fq2 :: new(
419
+ Fq :: from_str( "8495653923123431417604973247489272438418190587263600148770280649306958101930" )
420
+ . expect( "a valid field element" ) ,
421
+ Fq :: from_str( "4082367875863433681332203403145435568316851327593401208105741076214120093531" )
422
+ . expect( "a valid field element" ) ,
423
+ ) ,
424
+ ) . expect( "the generator P2(10857046999023057135944570762232829481370756359578518086990519993285655852781 + 11559732032986387107991004021392285783925812861821192530917403151452391805634i, 8495653923123431417604973247489272438418190587263600148770280649306958101930 + 4082367875863433681332203403145435568316851327593401208105741076214120093531i) is a valid curve point" ) ) ;
425
+ }
426
+
427
+ lazy_static ! {
428
+ pub static ref P1_P2_PAIRING : Gt = pairing( P1 . clone( ) , P2 . clone( ) ) ;
429
+ }
430
+ }
431
+
432
+ impl Impl for Bn128PairingImpl {
433
+ /// Can fail if:
434
+ /// - input length is not a multiple of 192
435
+ /// - any of odd points does not belong to bn128 curve
436
+ /// - any of even points does not belong to the twisted bn128 curve over the field F_p^2 = F_p[i] / (i^2 + 1)
437
+ fn execute ( & self , input : & [ u8 ] , output : & mut BytesRef ) -> Result < ( ) , Error > {
438
+ use bn:: { AffineG1 , AffineG2 , Fq , Fq2 , pairing, G1 , G2 , Gt } ;
439
+
440
+ let elements = input. len ( ) / 192 ; // (a, b_a, b_b - each 64-byte affine coordinates)
441
+ if input. len ( ) % 192 != 0 {
442
+ return Err ( "Invalid input length, must be multiple of 192 (3 * (32*2))" . into ( ) )
443
+ }
444
+ let ret_val = if input. len ( ) == 0 {
445
+ U256 :: one ( )
446
+ } else {
447
+ let mut vals = Vec :: new ( ) ;
448
+ for idx in 0 ..elements {
449
+ let a_x = Fq :: from_slice ( & input[ idx* 192 ..idx* 192 +32 ] )
450
+ . map_err ( |_| Error :: from ( "Invalid a argument x coordinate" ) ) ?;
451
+
452
+ let a_y = Fq :: from_slice ( & input[ idx* 192 +32 ..idx* 192 +64 ] )
453
+ . map_err ( |_| Error :: from ( "Invalid a argument y coordinate" ) ) ?;
454
+
455
+ let b_b_x = Fq :: from_slice ( & input[ idx* 192 +64 ..idx* 192 +96 ] )
456
+ . map_err ( |_| Error :: from ( "Invalid b argument imaginary coeff x coordinate" ) ) ?;
457
+
458
+ let b_b_y = Fq :: from_slice ( & input[ idx* 192 +96 ..idx* 192 +128 ] )
459
+ . map_err ( |_| Error :: from ( "Invalid b argument imaginary coeff y coordinate" ) ) ?;
460
+
461
+ let b_a_x = Fq :: from_slice ( & input[ idx* 192 +128 ..idx* 192 +160 ] )
462
+ . map_err ( |_| Error :: from ( "Invalid b argument real coeff x coordinate" ) ) ?;
463
+
464
+ let b_a_y = Fq :: from_slice ( & input[ idx* 192 +160 ..idx* 192 +192 ] )
465
+ . map_err ( |_| Error :: from ( "Invalid b argument real coeff y coordinate" ) ) ?;
466
+
467
+ vals. push ( (
468
+ G1 :: from (
469
+ AffineG1 :: new ( a_x, a_y) . map_err ( |_| Error :: from ( "Invalid a argument - not on curve" ) ) ?
470
+ ) ,
471
+ G2 :: from (
472
+ AffineG2 :: new (
473
+ Fq2 :: new ( b_a_x, b_a_y) ,
474
+ Fq2 :: new ( b_b_x, b_b_y) ,
475
+ ) . map_err ( |_| Error :: from ( "Invalid b argument - not on curve" ) ) ?
476
+ ) ,
477
+ ) ) ;
478
+ } ;
479
+
480
+ let mul = vals. into_iter ( ) . fold ( Gt :: one ( ) , |s, ( a, b) | s * pairing ( a, b) ) ;
481
+
482
+ if mul == * bn128_gen:: P1_P2_PAIRING {
483
+ U256 :: one ( )
484
+ } else {
485
+ U256 :: zero ( )
486
+ }
487
+ } ;
488
+
489
+ let mut buf = [ 0u8 ; 32 ] ;
490
+ ret_val. to_big_endian ( & mut buf) ;
491
+ output. write ( 0 , & buf) ;
492
+
493
+ Ok ( ( ) )
494
+ }
495
+ }
496
+
396
497
#[ cfg( test) ]
397
498
mod tests {
398
499
use super :: { Builtin , Linear , ethereum_builtin, Pricer , Modexp } ;
399
500
use ethjson;
400
501
use util:: { U256 , BytesRef } ;
502
+ use rustc_serialize:: hex:: FromHex ;
401
503
402
504
#[ test]
403
505
fn identity ( ) {
@@ -713,7 +815,82 @@ mod tests {
713
815
assert ! ( res. is_err( ) , "There should be built-in error here" ) ;
714
816
}
715
817
}
818
+
819
+ fn builtin_pairing ( ) -> Builtin {
820
+ Builtin {
821
+ pricer : Box :: new ( Linear { base : 0 , word : 0 } ) ,
822
+ native : ethereum_builtin ( "bn128_pairing" ) ,
823
+ activate_at : 0 ,
824
+ }
825
+ }
826
+
827
+ fn empty_test ( f : Builtin , expected : Vec < u8 > ) {
828
+ let mut empty = [ 0u8 ; 0 ] ;
829
+ let input = BytesRef :: Fixed ( & mut empty) ;
830
+
831
+ let mut output = vec ! [ 0u8 ; expected. len( ) ] ;
832
+
833
+ f. execute ( & input[ ..] , & mut BytesRef :: Fixed ( & mut output[ ..] ) ) . expect ( "Builtin should not fail" ) ;
834
+ assert_eq ! ( output, expected) ;
835
+ }
836
+
837
+ fn error_test ( f : Builtin , input : & [ u8 ] , msg_contains : Option < & str > ) {
838
+ let mut output = vec ! [ 0u8 ; 64 ] ;
839
+ let res = f. execute ( input, & mut BytesRef :: Fixed ( & mut output[ ..] ) ) ;
840
+ if let Some ( msg) = msg_contains {
841
+ if let Err ( e) = res {
842
+ if !e. 0 . contains ( msg) {
843
+ panic ! ( "There should be error containing '{}' here, but got: '{}'" , msg, e. 0 ) ;
844
+ }
845
+ }
846
+ } else {
847
+ assert ! ( res. is_err( ) , "There should be built-in error here" ) ;
848
+ }
849
+ }
850
+
851
+ fn bytes ( s : & ' static str ) -> Vec < u8 > {
852
+ FromHex :: from_hex ( s) . expect ( "static str should contain valid hex bytes" )
853
+ }
716
854
855
+ #[ test]
856
+ fn bn128_pairing_empty ( ) {
857
+ // should not fail, because empty input is a valid input of 0 elements
858
+ empty_test (
859
+ builtin_pairing ( ) ,
860
+ bytes ( "0000000000000000000000000000000000000000000000000000000000000001" ) ,
861
+ ) ;
862
+ }
863
+
864
+ #[ test]
865
+ fn bn128_pairing_notcurve ( ) {
866
+ // should fail - point not on curve
867
+ error_test (
868
+ builtin_pairing ( ) ,
869
+ & bytes ( "\
870
+ 1111111111111111111111111111111111111111111111111111111111111111\
871
+ 1111111111111111111111111111111111111111111111111111111111111111\
872
+ 1111111111111111111111111111111111111111111111111111111111111111\
873
+ 1111111111111111111111111111111111111111111111111111111111111111\
874
+ 1111111111111111111111111111111111111111111111111111111111111111\
875
+ 1111111111111111111111111111111111111111111111111111111111111111"
876
+ ) ,
877
+ Some ( "not on curve" ) ,
878
+ ) ;
879
+ }
880
+
881
+ #[ test]
882
+ fn bn128_pairing_fragmented ( ) {
883
+ // should fail - input length is invalid
884
+ error_test (
885
+ builtin_pairing ( ) ,
886
+ & bytes ( "\
887
+ 1111111111111111111111111111111111111111111111111111111111111111\
888
+ 1111111111111111111111111111111111111111111111111111111111111111\
889
+ 111111111111111111111111111111"
890
+ ) ,
891
+ Some ( "Invalid input length" ) ,
892
+ ) ;
893
+ }
717
894
718
895
#[ test]
719
896
#[ should_panic]
0 commit comments