Skip to content
This repository has been archived by the owner on Feb 27, 2023. It is now read-only.

Use integer division instead of floating-point division #16

Closed

Conversation

adlerjohn
Copy link
Member

Instead of rounding up by converting to float then back to int, do rounding-up integer division directly.

Based on https://stackoverflow.com/a/17974.

proofs.go Outdated
@@ -71,7 +70,7 @@ func (proof *SparseCompactMerkleProof) sanityCheck(th *treeHasher) bool {

// Compact proofs: check that the length of the bit mask is as expected
// according to NumSideNodes.
len(proof.BitMask) != int(math.Ceil(float64(proof.NumSideNodes)/float64(8))) ||
len(proof.BitMask) != (proof.NumSideNodes+8-1)/8 ||
Copy link
Member

Choose a reason for hiding this comment

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

What happens if NumSideNodes is MaxInt and do we need to worry about this?

Copy link
Member Author

Choose a reason for hiding this comment

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

There's already a sanity check (which should be called before trying to verify a proof): https://github.com/lazyledger/smt/blob/042131b944f99aafc1de3d9a34b982780878c418/proofs.go#L24-L25

Copy link
Member

@musalbas musalbas Feb 21, 2021

Choose a reason for hiding this comment

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

Hmm this does seem a bit dangerous as this is only safe because the above sanity check happens to be called before the the sanity check in this pull request. If someone refactors the code in the future, this could be overlooked and cause bugs.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree, but 1) it's safer than float division and 2) if it's an immediate concern we can add a test for max int. The true solution though is at the type level: define a new SaneSparseMerkleProof type that is only for internal functions, for which the sanity check is guaranteed to have been done. That way correctness can be guaranteed by the compiler at the type level, without having to rely on potentially-fragile unit tests. This should be done regardless since there are other places in the code that make assumptions on sanity checks having been done.

Copy link
Member Author

@adlerjohn adlerjohn Feb 22, 2021

Choose a reason for hiding this comment

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

Fixed in bce1912, which introduces a method that is guaranteed to not overflow and does not depend on other checks.

Copy link
Member

@musalbas musalbas Feb 22, 2021

Choose a reason for hiding this comment

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

Hmm introducing an extra function (or an extra test) now seems to overcomplicate things. I'd rather keep the original, which is better for readability.

Copy link
Member Author

@adlerjohn adlerjohn Feb 22, 2021

Choose a reason for hiding this comment

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

Still not comfortable with floating point math in this context, but looking into the behavior, it looks like there won't be an issue so long as the dividend is under 2**50 (2**53 minus 2**3 = 8 to handle the division). Which should never happen due to the sanity checks.

So, I'm okay with keeping the floating point division here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants