@@ -79,6 +79,13 @@ impl EcGroup {
7979 Ok ( ret)
8080 }
8181
82+ /// Initialize an EcGroup with custom group parameters.
83+ ///
84+ /// HAZMAT: This function DOES NOT perform a full check on parameters
85+ /// against all known attacks. The caller MUST make sure that parameters are
86+ /// trusted. Failing to comply with this requirement may result in the use
87+ /// of INSECURE curves. Prefer [EcGroup::new] with known curves listed in
88+ /// [EcGroupId].
8289 pub fn from_parameters (
8390 p : Mpi ,
8491 a : Mpi ,
@@ -96,15 +103,16 @@ impl EcGroup {
96103 let zero = Mpi :: new ( 0 ) ?;
97104
98105 // basic bounds checking
99- if & a <= & zero
106+ if & a < & zero
100107 || & a >= & p
101- || & b <= & zero
108+ || & b < & zero
102109 || & b >= & p
103- || & g_x <= & zero
110+ || & g_x < & zero
104111 || & g_x >= & p
105- || & g_y <= & zero
112+ || & g_y < & zero
106113 || & g_y >= & p
107114 || & order <= & zero
115+ || ( & a == & zero && & b == & zero)
108116 {
109117 return Err ( Error :: EcpBadInputData ) ;
110118 }
@@ -191,6 +199,8 @@ impl EcGroup {
191199 match self . group_id ( ) ? {
192200 EcGroupId :: Curve25519 => Ok ( 8 ) ,
193201 EcGroupId :: Curve448 => Ok ( 4 ) ,
202+ // Requires a point-counting algorithm such as SEA.
203+ EcGroupId :: None => Err ( Error :: EcpFeatureUnavailable ) ,
194204 _ => Ok ( 1 ) ,
195205 }
196206 }
@@ -754,4 +764,154 @@ mod tests {
754764 let pt3 = pt1. clone ( ) ;
755765 assert_eq ! ( pt2. eq( & pt3) . unwrap( ) , true ) ;
756766 }
767+
768+ #[ cfg( feature = "std" ) ]
769+ struct Params < ' a > {
770+ p : & ' a str ,
771+ a : & ' a str ,
772+ b : & ' a str ,
773+ g_x : & ' a str ,
774+ g_y : & ' a str ,
775+ n : & ' a str ,
776+ }
777+
778+ #[ cfg( feature = "std" ) ]
779+ impl Into < super :: Result < EcGroup > > for Params < ' _ > {
780+ fn into ( self ) -> super :: Result < EcGroup > {
781+ use std:: str:: FromStr ;
782+ EcGroup :: from_parameters (
783+ Mpi :: from_str ( self . p ) ?,
784+ Mpi :: from_str ( self . a ) ?,
785+ Mpi :: from_str ( self . b ) ?,
786+ Mpi :: from_str ( self . g_x ) ?,
787+ Mpi :: from_str ( self . g_y ) ?,
788+ Mpi :: from_str ( self . n ) ?,
789+ )
790+ }
791+ }
792+
793+ #[ test]
794+ #[ cfg( feature = "std" ) ]
795+ fn pathological_parameters ( ) {
796+ // y² = x³ mod 7 (note a == b == 0)
797+ let singular: super :: Result < _ > = Params {
798+ p : "0x07" ,
799+ a : "0x00" ,
800+ b : "0x00" ,
801+ g_x : "0x01" ,
802+ g_y : "0x02" ,
803+ n : "0x0b" ,
804+ } . into ( ) ;
805+ assert ! ( singular. is_err( ) ) ;
806+ }
807+
808+ #[ test]
809+ #[ cfg( feature = "std" ) ]
810+ fn bad_generators ( ) {
811+ // y² = x³ + x + 6 (mod 7) with bad generator (1, 2) and prime order 11
812+ let small_curve: super :: Result < _ > = Params {
813+ p : "0x07" ,
814+ a : "0x01" ,
815+ b : "0x06" ,
816+ g_x : "0x01" ,
817+ g_y : "0x02" ,
818+ n : "0x0b" ,
819+ } . into ( ) ;
820+ assert ! ( small_curve. is_err( ) ) ;
821+
822+ // y² = x³ + x + 6 (mod 7) with bad generator (0, 0) and prime order 11
823+ let small_curve_zero_gen: super :: Result < _ > = Params {
824+ p : "0x07" ,
825+ a : "0x01" ,
826+ b : "0x06" ,
827+ g_x : "0x00" ,
828+ g_y : "0x00" ,
829+ n : "0x0b" ,
830+ } . into ( ) ;
831+ assert ! ( small_curve_zero_gen. is_err( ) ) ;
832+ }
833+
834+ #[ test]
835+ #[ cfg( feature = "std" ) ]
836+ fn unknown_cofactor ( ) {
837+ // y² = x³ + x + 6 (mod 7) with generator (1, 6) and prime order 11
838+ let small_curve: super :: Result < _ > = Params {
839+ p : "0x07" ,
840+ a : "0x01" ,
841+ b : "0x06" ,
842+ g_x : "0x01" ,
843+ g_y : "0x06" ,
844+ n : "0x0b" ,
845+ } . into ( ) ;
846+ assert ! ( small_curve. unwrap( ) . cofactor( ) . is_err( ) ) ;
847+ }
848+
849+ #[ test]
850+ #[ cfg( feature = "std" ) ]
851+ fn zero_params_curves ( ) {
852+ use super :: Result ;
853+ // Barreto-Naehrig 254, note a = 0
854+ let bn254: Result < _ > = Params {
855+ p : "0x2523648240000001BA344D80000000086121000000000013A700000000000013" ,
856+ a : "0x0000000000000000000000000000000000000000000000000000000000000000" ,
857+ b : "0x0000000000000000000000000000000000000000000000000000000000000002" ,
858+ g_x : "0x2523648240000001BA344D80000000086121000000000013A700000000000012" ,
859+ g_y : "0x0000000000000000000000000000000000000000000000000000000000000001" ,
860+ n : "0x2523648240000001BA344D8000000007FF9F800000000010A10000000000000D" ,
861+ } . into ( ) ;
862+ assert ! ( bn254. is_ok( ) ) ;
863+
864+ // Prescribed embedded degree of 12, BLS12-381
865+ let bls12_381: Result < _ > = Params {
866+ p : "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab" ,
867+ a : "0x00" ,
868+ b : "0x04" ,
869+ g_x : "0x17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB" ,
870+ g_y : "0x08B3F481E3AAA0F1A09E30ED741D8AE4FCF5E095D5D00AF600DB18CB2C04B3EDD03CC744A2888AE40CAA232946C5E7E1" ,
871+ n : "0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001" ,
872+ } . into ( ) ;
873+ assert ! ( bls12_381. is_ok( ) ) ;
874+
875+ // Fp256BN
876+ let fp256_bn: Result < _ > = Params {
877+ p : "0xfffffffffffcf0cd46e5f25eee71a49f0cdc65fb12980a82d3292ddbaed33013" ,
878+ a : "0x00" ,
879+ b : "0x03" ,
880+ g_x : "0x01" ,
881+ g_y : "0x02" ,
882+ n : "0xfffffffffffcf0cd46e5f25eee71a49e0cdc65fb1299921af62d536cd10b500d" ,
883+ } . into ( ) ;
884+ assert ! ( fp256_bn. is_ok( ) ) ;
885+
886+ // id-GostR3410-2001-CryptoPro-C-ParamSet, note g_x = 0
887+ let gost_r3410: Result < _ > = Params {
888+ p : "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b" ,
889+ a : "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598" ,
890+ b : "0x805a" ,
891+ g_x : "0x00" ,
892+ g_y : "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67" ,
893+ n : "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9" ,
894+ } . into ( ) ;
895+ assert ! ( gost_r3410. is_ok( ) ) ;
896+
897+ // secp256k1 (Bitcoin), note a = 0
898+ let my_secp256k1: Result < EcGroup > = Params {
899+ p : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" ,
900+ a : "0x0000000000000000000000000000000000000000000000000000000000000000" ,
901+ b : "0x0000000000000000000000000000000000000000000000000000000000000007" ,
902+ g_x : "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" ,
903+ g_y : "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" ,
904+ n : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" ,
905+ } . into ( ) ;
906+ assert ! ( my_secp256k1. is_ok( ) ) ;
907+ let my_secp256k1 = my_secp256k1. unwrap ( ) ;
908+
909+ // We compare against the known SecP256K1
910+ let secp256k1 = EcGroup :: new ( EcGroupId :: SecP256K1 ) . unwrap ( ) ;
911+ assert ! ( my_secp256k1. p( ) == secp256k1. p( ) ) ;
912+ assert ! ( my_secp256k1. a( ) == secp256k1. a( ) ) ;
913+ assert ! ( my_secp256k1. b( ) == secp256k1. b( ) ) ;
914+ assert ! ( my_secp256k1. generator( ) == secp256k1. generator( ) ) ;
915+ assert ! ( my_secp256k1. order( ) == secp256k1. order( ) ) ;
916+ }
757917}
0 commit comments