PHP 位移位意外 Results/Overflow?
PHP Bit shift Unexpected Results/Overflow?
在我正在编写的一个小脚本中,我使用了以下函数:
function ROTR( $x, $t ){
return( $x >> $t ) | ( $x << ( 32 - $t ) );
}
function Σ0( $x ){
echo("SIG INPUT: " . $x . "<br>" );
$s0 = ROTR( $x, 2 );
$s1 = ROTR( $x, 13 );
$s2 = ROTR( $x, 22 );
echo( "SIGMA0 2: " . $s0 . "<br>" );
echo( "SIGMA0 13: " . $s1 . "<br>" );
echo( "SIGMA0 22: " . $s2 . "<br>" );
return ( $s0 ^ $s1 ^ $s2 );
}
这些都在第 5 页和第 10 页的 this document 中定义
我应用以下方法并得到这些结果:
Σ0( 1779033703 )
> SIG INPUT: 1779033703
> SIGMA0 2: -628983399
> SIGMA0 13: 859525199
> SIGMA0 22: 664378792
输入完全正常,最后两个(SIGMA0 13
和 SIGMA0 22
)也是如此,但是 ROTR( 1779033703, 2 )
移位似乎超出了 2^31-1
signed int 限制.
我期望的值是3665983897
,我能够在VB.Net中获得:
' THIS SCRIPT HAS INTEGER OVERFLOW CHECKS DISABLED!
Function RotRight(x As UInt32, count As UInt32) As UInt32
Dim t5 = x \ (2 ^ count)
Dim t6 = x * (2 ^ (32 - count))
Return (t5 Or t6)
End Function
Function EP0(x As UInt32) As UInt32
Dim t7 = RotRight(x, 2)
Dim t8 = RotRight(x, 13)
Dim t9 = RotRight(x, 22)
Return (t7 Xor t8 Xor t9)
End Function
>
SIG INPUT: 1779033703
SIGMA0 2: 3665983897
SIGMA0 13: 859525199
SIGMA0 22: 664378792
我读到有几种方法可以通过 gmp 库将整数视为字符串来规避溢出问题,但我还没有找到可行的方法。
到目前为止,我已尝试将整数转换为字符串,然后使用 gmp_init( string )
将字符串转换为 GMP 编号,但该库似乎不支持位移。
PS:我正在使用 PHP 的 32 位版本(我在 Windows 使用 XAMPP,它还不支持 64 位)
因为您安装的是 32 位 PHP,并且 PHP 不支持无符号整数,您将需要使用像 GMP 这样的库来解决您的问题。不幸的是,GMP 没有移位算术函数,但是您可以使用除法和乘法来模拟它们:
function ROTR( $x, $t ){
return gmp_and(gmp_or(gmp_div($x, 1 << $t), gmp_mul($x, 1 << (32 - $t))), "4294967295");
}
function Σ0( $x ){
echo("SIG INPUT: " . $x . "\n" );
$s0 = ROTR( $x, 2 );
$s1 = ROTR( $x, 13 );
$s2 = ROTR( $x, 22 );
echo( "SIGMA0 2: " . gmp_strval($s0, 10) . "\n" );
echo( "SIGMA0 13: " . gmp_strval($s1, 10) . "\n" );
echo( "SIGMA0 22: " . gmp_strval($s2, 10) . "\n" );
return ( gmp_xor($s0, gmp_xor($s1, $s2)) );
}
Σ0( 1779033703 );
注意,因为GMP是任意精度的,所以需要屏蔽ROTR
的输出,通过按位and'ing
将其限制为32位(1 << 32) - 1
。
输出:
SIG INPUT: 1779033703
SIGMA0 2: 3665983897
SIGMA0 13: 859525199
SIGMA0 22: 664378792
这是 3v4l
上的演示
在我正在编写的一个小脚本中,我使用了以下函数:
function ROTR( $x, $t ){
return( $x >> $t ) | ( $x << ( 32 - $t ) );
}
function Σ0( $x ){
echo("SIG INPUT: " . $x . "<br>" );
$s0 = ROTR( $x, 2 );
$s1 = ROTR( $x, 13 );
$s2 = ROTR( $x, 22 );
echo( "SIGMA0 2: " . $s0 . "<br>" );
echo( "SIGMA0 13: " . $s1 . "<br>" );
echo( "SIGMA0 22: " . $s2 . "<br>" );
return ( $s0 ^ $s1 ^ $s2 );
}
这些都在第 5 页和第 10 页的 this document 中定义
我应用以下方法并得到这些结果:
Σ0( 1779033703 )
> SIG INPUT: 1779033703
> SIGMA0 2: -628983399
> SIGMA0 13: 859525199
> SIGMA0 22: 664378792
输入完全正常,最后两个(SIGMA0 13
和 SIGMA0 22
)也是如此,但是 ROTR( 1779033703, 2 )
移位似乎超出了 2^31-1
signed int 限制.
我期望的值是3665983897
,我能够在VB.Net中获得:
' THIS SCRIPT HAS INTEGER OVERFLOW CHECKS DISABLED!
Function RotRight(x As UInt32, count As UInt32) As UInt32
Dim t5 = x \ (2 ^ count)
Dim t6 = x * (2 ^ (32 - count))
Return (t5 Or t6)
End Function
Function EP0(x As UInt32) As UInt32
Dim t7 = RotRight(x, 2)
Dim t8 = RotRight(x, 13)
Dim t9 = RotRight(x, 22)
Return (t7 Xor t8 Xor t9)
End Function
>
SIG INPUT: 1779033703
SIGMA0 2: 3665983897
SIGMA0 13: 859525199
SIGMA0 22: 664378792
我读到有几种方法可以通过 gmp 库将整数视为字符串来规避溢出问题,但我还没有找到可行的方法。
到目前为止,我已尝试将整数转换为字符串,然后使用 gmp_init( string )
将字符串转换为 GMP 编号,但该库似乎不支持位移。
PS:我正在使用 PHP 的 32 位版本(我在 Windows 使用 XAMPP,它还不支持 64 位)
因为您安装的是 32 位 PHP,并且 PHP 不支持无符号整数,您将需要使用像 GMP 这样的库来解决您的问题。不幸的是,GMP 没有移位算术函数,但是您可以使用除法和乘法来模拟它们:
function ROTR( $x, $t ){
return gmp_and(gmp_or(gmp_div($x, 1 << $t), gmp_mul($x, 1 << (32 - $t))), "4294967295");
}
function Σ0( $x ){
echo("SIG INPUT: " . $x . "\n" );
$s0 = ROTR( $x, 2 );
$s1 = ROTR( $x, 13 );
$s2 = ROTR( $x, 22 );
echo( "SIGMA0 2: " . gmp_strval($s0, 10) . "\n" );
echo( "SIGMA0 13: " . gmp_strval($s1, 10) . "\n" );
echo( "SIGMA0 22: " . gmp_strval($s2, 10) . "\n" );
return ( gmp_xor($s0, gmp_xor($s1, $s2)) );
}
Σ0( 1779033703 );
注意,因为GMP是任意精度的,所以需要屏蔽ROTR
的输出,通过按位and'ing
将其限制为32位(1 << 32) - 1
。
输出:
SIG INPUT: 1779033703
SIGMA0 2: 3665983897
SIGMA0 13: 859525199
SIGMA0 22: 664378792
这是 3v4l
上的演示