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

crypto(fixpoint): add overflow failure test #2559

Merged
merged 2 commits into from
May 14, 2023
Merged

crypto(fixpoint): add overflow failure test #2559

merged 2 commits into from
May 14, 2023

Conversation

erwanor
Copy link
Member

@erwanor erwanor commented May 13, 2023

This test should fail and overflow loudly, but instead it fails silently producing a nonsensical value.

@erwanor erwanor temporarily deployed to smoke-test May 13, 2023 03:30 — with GitHub Actions Inactive
@hdevalence
Copy link
Member

hdevalence commented May 13, 2023

The bug is in this code I wrote in U128x128::checked_mul:

        x1y1.checked_shl(128)
            .and_then(|acc| acc.checked_add(x0y1))
            .and_then(|acc| acc.checked_add(x1y0))
            .and_then(|acc| acc.checked_add(x0y0 >> 128))
            .map(U128x128)

The first call was intended to return None when there are nonzero bits in the high part of the product. But that's not what checked_shl does: the check is on the shift amount, not the shifted bits. Oops.

To remediate this, we should:

  • Use U256::into_words to split the high and low parts of x1y1, and check that the high part is zero, erroring out if so
  • Add a fixpoint::Error enum with an Error::Overflow variant using thiserror, and swap out the use of Options in the U128x128 API for Results
  • Make a plan of how to review use of the U128x128 arithmetic in the DEX code to check that it either doesn't overflow or errors out semi-gracefully

@hdevalence
Copy link
Member

(The last point can be a followup issue)

@erwanor erwanor self-assigned this May 13, 2023
The bug was in this code:
```
        x1y1.checked_shl(128)
            .and_then(|acc| acc.checked_add(x0y1))
            .and_then(|acc| acc.checked_add(x1y0))
            .and_then(|acc| acc.checked_add(x0y0 >> 128))
            .map(U128x128)
```
The first call was intended to return None when there are nonzero bits in the
high part of the product. But that's not what checked_shl does: the check is on
the shift amount, not the shifted bits. Oops.

Longer-term, we should expand the `Error` type to have numeric errors, and
change the arithmetic operations to return `Result`s. For now, we can correct
this bug and see what other errors in our stack it was hiding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants