Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uint: Fix overflowing_neg by implementing two's complement #611

Merged
merged 3 commits into from
Feb 4, 2022

Conversation

lenerd
Copy link
Contributor

@lenerd lenerd commented Jan 16, 2022

The operation overflowing_neg on the primitive integer types in the
Rust standard library computes the negation of the integer value using
two's complement, i.e., it returns !self + 1.

The current implementation of the uint library implemented
overflowing_neg using !self for non-zero values which is bit-wise
negation (NOT). This lead to behavior where 0 - 1 != -1 for
U256 with the overflowing_neg and overflow_sub operations.

This patch adapts the uint_overflowing_binop macro to implement the
two's complement correctly: Starting from the least significant word
we apply u64::overflowing_neg until we have seen the first one-bit in
the original integer, i.e., until overflowing_neg reports an overflow.
Then we use bit-wise NOT for the remaining words
(cf. https://en.wikipedia.org/wiki/Two%27s_complement#Working_from_LSB_towards_MSB).

The operation `overflowing_neg` on the primitive integer types in the
Rust standard library computes the negation of the integer value using
two's complement, i.e., it returns `!self + 1`.

The previous implementation of the uint library implemented
`overflowing_neg` using `!self` for non-zero values which is bit-wise
negation (NOT).  This lead to behavior where 0 - 1 != -1 for U256 with
the `overflowing_neg` and `overflow_sub` operations.

This patch adapts the `uint_overflowing_binop` macro to implement the
two's complement correctly: Starting from the least significant word
we apply `u64::overflowing_neg` until we have seen the first one-bit in
the original integer, i.e., until `overflowing_neg` reports an overflow.
Then we use bit-wise NOT for the remaining words.
@ordian ordian added the waiting-on-review The PR needs to be reviewed label Jan 17, 2022
Copy link
Member

@ordian ordian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!
Thanks for adding the test as well.
Regarding the implementation, instead of duplicating the macro, I'd rather change the current implementation from !self to !self + 1 even if it's not as performant. We should prioritize simplicity and correctness here.

@ordian ordian added waiting-on-author The author needs to address review and removed waiting-on-review The PR needs to be reviewed labels Feb 4, 2022
uint/src/uint.rs Outdated Show resolved Hide resolved
uint/src/uint.rs Outdated Show resolved Hide resolved
@ordian ordian added changelog Needs to be added to the changelog and removed waiting-on-author The author needs to address review labels Feb 4, 2022
@ordian ordian merged commit b37d0b3 into paritytech:master Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog Needs to be added to the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants