Skip to content

Commit 4714da6

Browse files
Ensure public key is on the prime order subgroup
1 parent 547e2dc commit 4714da6

2 files changed

Lines changed: 27 additions & 4 deletions

File tree

‎src/Core/Ed25519.php‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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',

‎src/File.php‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,12 @@ public static function verify(string $sig, string $filePath, string $publicKey):
630630
ParagonIE_Sodium_Compat::$fastMult = true;
631631

632632
$A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey);
633+
if (ParagonIE_Sodium_Core_Ed25519::small_order($publicKey)) {
634+
throw new SodiumException('Public key has small order');
635+
}
636+
if (!ParagonIE_Sodium_Core_Ed25519::is_on_main_subgroup($A)) {
637+
throw new SodiumException('Public key is not on main subgroup');
638+
}
633639

634640
$hs = hash_init('sha512');
635641
hash_update($hs, self::substr($sig, 0, 32));

0 commit comments

Comments
 (0)