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

More error correction preparation (upgrades to Field, Polynomial, InvalidResidueError and others) #202

Closed
wants to merge 10 commits into from

Conversation

apoelstra
Copy link
Member

This PR has a fairly large diff but the commits should be self-contained and much of the diff consists of comments. In particular this introduces a new type FieldVec to back Polynomial, which strives to provide a sensible API even in a no-alloc case:

  • With an allocator, arbitrarily-large vectors (and therefore arbitrarily large checksums) are supported.
  • Without an allocator, the FieldVec type panics for large checksums, but since it is only (planned to be) used in error correction, it should be easy to detect this up front and provide a sensible error to the user.

The threshold for "large" is currently set at "bigger than bech32", but it is easy to change this and even easy to add a feature-gate.

I believe this completes all the changes to the traits needed for error correction, and the next PR can just implement correction.

This is purely a code refactor to get rid of a `use` statement (which
will trigger an "unused code" warning if the macro is ever called
somewhere where the Field trait is already in scope). As a side effect
it reduces the size of the macro by roughly 75% in terms of line count.
Several methods (and we are going to add more) don't really belong in a
general-purpose field trait, which really is just "a type that can be
multiplied and added and has some associated constants".

This isn't a general-purpose math library, but fields are a pretty
common thing for people to want. And it's pretty easy for us to expose
this trait in a nice way, so we might as well do it.
This will make it easier for PrintImpl to output error correction
parameters.

Since this is an implementation detail of the library, stick it into the
Bech32Field trait rather than the Field one.
In the next commits we'll introduce a generic no-alloc container called
FieldVec whose implementation will be much nicer if we have a Default
bound on all of our field elements. This way we can implement the
"FieldVec", which despite the name really has nothing to do with fields,
purely in terms of core traits, rather than confusing readers of the
code by having Field bounds everywhere without ever doing algebra.

Since fields all have a ZERO member, which is a sensible output for
Default, this bound is reasonable to require.
This adds some new methods to Field, which have default impls and are
therefore non-breaking. (And they are general-purpose "field" things.)
This will allow `Polynomial` to work without an allocator (at least for
"small" checksums, including every checksum supported by this library).
Here a "small" checksum is one of length at most 6 (which covers bech32
and bech32m).

codex32 (13 characters) and "long codex32" (15 characters) will not work
with no-alloc. I would kinda like to fix this but it results in large
types, especially a large InvalidResidueError type, so probably it will
need to be feature-gated or something. For now we just punt on it.
We can now use `PrintImpl` even without an allocator. This is of limited
use of course, but it paves the ground for use to do error correction
without an allocator, which is interesting.
We are going to want to extend the ChecksumError::InvalidResidue error
variant to allow error correction, and in order to do so, we need to know
the actual residue computed from a string, not just that the residue failed
to match the target.

Uses the `Polynomial` type; see the previous commits for some caveats
about this type when alloc is disabled. (Prior to this PR, you just
couldn't use Polynomial at all without alloc.)

As an initial application of the new error, avoid re-validating
a bech32 address to handle the distinction between bech32m and
bech32. Instead, if bech32m validation fails, check if the
"bad" residue actually matches the bech32 target. If so, accept.

On my system this reduces the `bech32_parse_address` benchmark
from 610ns to 455ns, more than a 33% speedup.
@apoelstra
Copy link
Member Author

CI failed because I had a doccomment referring to a field of Checksum that didn't yet exist. Backported the commit that introduced it.

But now this PR is way too big :). Gonna close it and split it.

@apoelstra apoelstra closed this Sep 18, 2024
@apoelstra apoelstra deleted the 2024-09--fieldvec branch September 18, 2024 15:42
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.

1 participant