@@ -115,6 +115,20 @@ public static function publickey_from_secretkey(
115115 return self ::sk_to_pk ($ sk );
116116 }
117117
118+ /**
119+ * Returns TRUE if $A represents a point on the order of the Edwards25519 prime order subgroup.
120+ * Returns FALSE if $A is on a different subgroup.
121+ *
122+ * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
123+ * @return bool
124+ */
125+ public static function is_on_main_subgroup (ParagonIE_Sodium_Core_Curve25519_Ge_P3 $ A ): bool
126+ {
127+ $ p1 = self ::ge_mul_l ($ A );
128+ $ t = self ::fe_sub ($ p1 ->Y , $ p1 ->Z );
129+ return self ::fe_isnonzero ($ p1 ->X ) && self ::fe_isnonzero ($ t );
130+ }
131+
118132 /**
119133 * @param string $pk
120134 * @return string
@@ -131,9 +145,9 @@ public static function pk_to_curve25519(
131145 throw new SodiumException ('Public key is on a small order ' );
132146 }
133147 $ A = self ::ge_frombytes_negate_vartime (self ::substr ($ pk , 0 , 32 ));
134- $ p1 = self :: ge_mul_l ( $ A );
135- if (!self ::fe_isnonzero ( $ p1 -> X )) {
136- throw new SodiumException ('Unexpected zero result ' );
148+ // check that A * L == identity point
149+ if (!self ::is_on_main_subgroup ( $ A )) {
150+ throw new SodiumException ('Public key is not on a member of the main subgroup ' );
137151 }
138152 $ one_minux_y = self ::fe_invert (
139153 self ::fe_sub (
@@ -283,7 +297,7 @@ public static function verify_detached(
283297 throw new SodiumException ('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long ' );
284298 }
285299 if ((self ::chrToInt ($ sig [63 ]) & 240 ) && self ::check_S_lt_L (self ::substr ($ sig , 32 , 32 ))) {
286- throw new SodiumException ('S < L - Invalid signature ' );
300+ throw new SodiumException ('S >= L - Invalid signature ' );
287301 }
288302 if (self ::small_order ($ sig )) {
289303 throw new SodiumException ('Signature is on too small of an order ' );
@@ -306,6 +320,9 @@ public static function verify_detached(
306320 ParagonIE_Sodium_Compat::$ fastMult = true ;
307321
308322 $ A = self ::ge_frombytes_negate_vartime ($ pk );
323+ if (!self ::is_on_main_subgroup ($ A )) {
324+ throw new SodiumException ('Public key is not on main subgroup ' );
325+ }
309326
310327 $ hDigest = hash (
311328 'sha512 ' ,
0 commit comments