@@ -3263,11 +3263,17 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount)
3263
3263
{
3264
3264
bits = new ReadOnlySpan < uint > ( in smallBits ) ;
3265
3265
}
3266
- int xl = bits . Length ;
3267
3266
3268
- if ( negx && bits [ ^ 1 ] >= kuMaskHighBit
3269
- && ! ( bits . IndexOfAnyExcept ( 0u ) == bits . Length - 1 && bits [ ^ 1 ] == kuMaskHighBit ) )
3267
+ int xl = bits . Length ;
3268
+ if ( negx && ( bits [ ^ 1 ] >= kuMaskHighBit ) && ( ( bits [ ^ 1 ] != kuMaskHighBit ) || bits . IndexOfAnyExcept ( 0u ) != ( bits . Length - 1 ) ) )
3269
+ {
3270
+ // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
3271
+ // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
3272
+ // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
3273
+ // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
3274
+ // If the 2's component's last element is a 0, we will track the sign externally
3270
3275
++ xl ;
3276
+ }
3271
3277
3272
3278
int byteCount = xl * 4 ;
3273
3279
@@ -3412,11 +3418,17 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3412
3418
{
3413
3419
bits = new ReadOnlySpan < uint > ( in smallBits ) ;
3414
3420
}
3415
- int xl = bits . Length ;
3416
3421
3417
- if ( negx && bits [ ^ 1 ] >= kuMaskHighBit
3418
- && ! ( bits . IndexOfAnyExcept ( 0u ) == bits . Length - 1 && bits [ ^ 1 ] == kuMaskHighBit ) )
3422
+ int xl = bits . Length ;
3423
+ if ( negx && ( bits [ ^ 1 ] >= kuMaskHighBit ) && ( ( bits [ ^ 1 ] != kuMaskHighBit ) || bits . IndexOfAnyExcept ( 0u ) != ( bits . Length - 1 ) ) )
3424
+ {
3425
+ // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
3426
+ // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
3427
+ // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
3428
+ // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
3429
+ // If the 2's component's last element is a 0, we will track the sign externally
3419
3430
++ xl ;
3431
+ }
3420
3432
3421
3433
int byteCount = xl * 4 ;
3422
3434
@@ -3505,11 +3517,11 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3505
3517
dstIndex -- ;
3506
3518
srcIndex -- ;
3507
3519
}
3508
- while ( ( uint ) srcIndex < ( uint ) xd . Length ) ;
3520
+ while ( ( uint ) srcIndex < ( uint ) xd . Length ) ; // is equivalent to (srcIndex >= 0 && srcIndex < xd.Length)
3509
3521
3510
3522
srcIndex = xd . Length - 1 ;
3511
3523
3512
- while ( ( uint ) dstIndex < ( uint ) zd . Length )
3524
+ while ( ( uint ) dstIndex < ( uint ) zd . Length ) // is equivalent to (dstIndex >= 0 && dstIndex < zd.Length)
3513
3525
{
3514
3526
uint part = xd [ srcIndex ] ;
3515
3527
0 commit comments