Skip to content

Unexpected result on Rsh #8

@IsraelGomes

Description

@IsraelGomes

Hello.
I was using the Rsh method and came across an unexpected behavior. I think this code might reproduce the problem.
I am comparing it with uint256.

valueU256 := uint256.MustFromDecimal("6276865796315986613307619852238232712866172378830163935232")
fmt.Println("Result uint256:", valueU256.Rsh(valueU256, 128).Dec())
valueI256 := int256.MustFromDec("6276865796315986613307619852238232712866172378830163935232")
fmt.Println("Result int256:", valueI256.Rsh(valueI256, 128).Dec())

The code produce this result:

Result uint256: 18446050711097703530
Result int256: 0

A Rsh operation where z and x are same have that error, but if we use a new receiver as below it does not happen.

valueU256 := uint256.MustFromDecimal("6276865796315986613307619852238232712866172378830163935232")
fmt.Println("Result uint256:", valueU256.Rsh(valueU256, 128).Dec())
valueI256 := int256.MustFromDec("6276865796315986613307619852238232712866172378830163935232")
fmt.Println("Result int256:", new(int256.Int).Rsh(valueI256, 128).Dec())

The result is the same as uint256.

Result uint256: 18446050711097703530
Result int256: 18446050711097703530

I think it has to do with the order some things are done here:

func (z *Int) rsh(x *Int, n uint) *Int {
	if n >= 255 {
		return z.Clear()
	}
	switch {
	case n >= 192:
		n -= 192
		z[3], z[2], z[1], z[0] = 0, 0, 0, x[3]>>n
	case n >= 128:
		n -= 128
		z[3], z[2] = 0, 0// If z and x are the same reference, then this will change x[3] and x[2] as well
		z[1] = x[3] >> n // causing this to be z[1] = 0 >> n.
		z[0] = (x[3] << (64 - n)) | (x[2] >> n) // and this to be (0 << (64 - n)) | (0 >> n).
	case n >= 64:
// I think this case have the same problem as the previous one.
		n -= 64
		z[3] = 0
		z[2] = x[3] >> n
		z[1] = (x[3] << (64 - n)) | (x[2] >> n)
		z[0] = (x[2] << (64 - n)) | (x[1] >> n)
	default:
		z[3] = x[3] >> n
		z[2] = (x[3] << (64 - n)) | (x[2] >> n)
		z[1] = (x[2] << (64 - n)) | (x[1] >> n)
		z[0] = (x[1] << (64 - n)) | (x[0] >> n)
	}
	return `z`
}

It worked when I changed to:

func (z *Int) rsh(x *Int, n uint) *Int {
	if n >= 255 {
		return z.Clear()
	}
	switch {
	case n >= 192:
		n -= 192
		z[3], z[2], z[1], z[0] = 0, 0, 0, x[3]>>n
	case n >= 128:
		n -= 128
		z[0] = (x[3] << (64 - n)) | (x[2] >> n)
		z[1] = x[3] >> n
		z[3], z[2] = 0, 0
	case n >= 64:
		n -= 64
		z[0] = (x[2] << (64 - n)) | (x[1] >> n)
		z[1] = (x[3] << (64 - n)) | (x[2] >> n)
		z[2] = x[3] >> n
		z[3] = 0
	default:
		z[0] = (x[1] << (64 - n)) | (x[0] >> n)
		z[1] = (x[2] << (64 - n)) | (x[1] >> n)
		z[2] = (x[3] << (64 - n)) | (x[2] >> n)
		z[3] = x[3] >> n
	}
	return z
}

I hope this can help somehow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions