Skip to content

Commit b4b6d76

Browse files
committed
fix: gmpToBytes no longer falls into the PHP "0" Elvis-falsy trap
For FF1 values where gmp_strval($val, 16) produced exactly "30", the prior `hex2bin($hex) ?: "\x00"` would round-trip the bytes through ASCII text. The result, the single byte 0x30, equals the string "0" — one of PHP's handful of falsy strings — so the Elvis operator silently swapped it for NUL. The bug fired any time a half-block's integer value happened to equal 48 and gmpToBytes was asked for a fixed-width byte string. In FF1 that shows up in the Q block, corrupting one round's PRF input and every round after. The output stayed self-consistent (encrypt/decrypt are still inverses) so a roundtrip test passed; only a cross-language comparison surfaced it. The cyphera adversarial FF1 b-matrix (radix 10, length 6, plaintext '307418', case 22) hit it on round 5 of encryption: B = [0,4,8] → num(B) = 48 → numB silently became 0x0000 instead of 0x0030, and the ciphertext diverged from every other Cyphera SDK. Fixed by switching to gmp_export with explicit byte-order flags, so the path never goes through PHP's loose-typing.
1 parent 29e465e commit b4b6d76

1 file changed

Lines changed: 7 additions & 4 deletions

File tree

src/FF1.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,14 @@ private function buildQ(string $T, int $i, string $numBytes, int $b): string
170170

171171
private function gmpToBytes(\GMP $val, int $len): string
172172
{
173-
$hex = gmp_strval($val, 16);
174-
if (strlen($hex) % 2 !== 0) {
175-
$hex = '0' . $hex;
173+
// Use gmp_export rather than gmp_strval(…,16)+hex2bin: the latter
174+
// round-trips through ASCII text, and when the result happens to be the
175+
// single byte 0x30 ('0'), PHP's Elvis operator treated it as falsy and
176+
// replaced it with NUL — silently corrupting the FF1 Q block.
177+
if (gmp_cmp($val, 0) === 0) {
178+
return str_repeat("\x00", $len > 0 ? $len : 1);
176179
}
177-
$bytes = hex2bin($hex) ?: "\x00";
180+
$bytes = gmp_export($val, 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
178181
if (strlen($bytes) < $len) {
179182
$bytes = str_repeat("\x00", $len - strlen($bytes)) . $bytes;
180183
}

0 commit comments

Comments
 (0)