@@ -3247,11 +3247,18 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount)
3247
3247
{
3248
3248
bits = new ReadOnlySpan < uint > ( in smallBits ) ;
3249
3249
}
3250
- int xl = bits . Length ;
3251
3250
3252
- if ( negx && bits [ ^ 1 ] >= kuMaskHighBit
3253
- && ! ( bits . IndexOfAnyExcept ( 0u ) == bits . Length - 1 && bits [ ^ 1 ] == kuMaskHighBit ) )
3251
+ int xl = bits . Length ;
3252
+ if ( negx && ( bits [ ^ 1 ] >= kuMaskHighBit ) && ( ( bits [ ^ 1 ] != kuMaskHighBit ) || bits . IndexOfAnyExcept ( 0u ) != ( bits . Length - 1 ) ) )
3253
+ {
3254
+ // For a shift of N x 32 bit,
3255
+ // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
3256
+ // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
3257
+ // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
3258
+ // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
3259
+ // If the 2's component's last element is a 0, we will track the sign externally
3254
3260
++ xl ;
3261
+ }
3255
3262
3256
3263
int byteCount = xl * 4 ;
3257
3264
@@ -3396,11 +3403,18 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3396
3403
{
3397
3404
bits = new ReadOnlySpan < uint > ( in smallBits ) ;
3398
3405
}
3399
- int xl = bits . Length ;
3400
3406
3401
- if ( negx && bits [ ^ 1 ] >= kuMaskHighBit
3402
- && ! ( bits . IndexOfAnyExcept ( 0u ) == bits . Length - 1 && bits [ ^ 1 ] == kuMaskHighBit ) )
3407
+ int xl = bits . Length ;
3408
+ if ( negx && ( bits [ ^ 1 ] >= kuMaskHighBit ) && ( ( bits [ ^ 1 ] != kuMaskHighBit ) || bits . IndexOfAnyExcept ( 0u ) != ( bits . Length - 1 ) ) )
3409
+ {
3410
+ // For a shift of N x 32 bit,
3411
+ // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
3412
+ // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
3413
+ // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
3414
+ // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
3415
+ // If the 2's component's last element is a 0, we will track the sign externally
3403
3416
++ xl ;
3417
+ }
3404
3418
3405
3419
int byteCount = xl * 4 ;
3406
3420
@@ -3489,11 +3503,11 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3489
3503
dstIndex -- ;
3490
3504
srcIndex -- ;
3491
3505
}
3492
- while ( ( uint ) srcIndex < ( uint ) xd . Length ) ;
3506
+ while ( ( uint ) srcIndex < ( uint ) xd . Length ) ; // is equivalent to (srcIndex >= 0 && srcIndex < xd.Length)
3493
3507
3494
3508
srcIndex = xd . Length - 1 ;
3495
3509
3496
- while ( ( uint ) dstIndex < ( uint ) zd . Length )
3510
+ while ( ( uint ) dstIndex < ( uint ) zd . Length ) // is equivalent to (dstIndex >= 0 && dstIndex < zd.Length)
3497
3511
{
3498
3512
uint part = xd [ srcIndex ] ;
3499
3513
0 commit comments