checksum: introduce PrintImpl object that can compute various code properties#180
Conversation
6ea3734 to
eea45d6
Compare
|
I updated the API files inline with each commit so it's clear what commits change the API in what ways. Let me know if it'd be better to pull these out into their own commit(s). |
a929a57 to
6c386ab
Compare
|
This is ready for review. I extended it a bit to support the descriptor checksum but I'll stop extending it and do future changes in a later PR. |
tcharding
left a comment
There was a problem hiding this comment.
That was a pleasure to review, the code is super clean. Code review only, no clue if the math is right :)
| + ops::Add<Self, Output = Self> | ||
| + for<'a> ops::Add<&'a Self, Output = Self> | ||
| + ops::Sub<Self, Output = Self> | ||
| + ops::AddAssign | ||
| + for<'a> ops::AddAssign<&'a Self> | ||
| + for<'a> ops::Sub<&'a Self, Output = Self> | ||
| + ops::SubAssign | ||
| + for<'a> ops::SubAssign<&'a Self> | ||
| + ops::Mul<Self, Output = Self> | ||
| + for<'a> ops::Mul<&'a Self, Output = Self> | ||
| + ops::MulAssign | ||
| + for<'a> ops::MulAssign<&'a Self> | ||
| + ops::Div<Self, Output = Self> | ||
| + for<'a> ops::Div<&'a Self, Output = Self> | ||
| + ops::DivAssign | ||
| + for<'a> ops::DivAssign<&'a Self> | ||
| + ops::Neg |
There was a problem hiding this comment.
All the references are a bit noisy, I found this order is easier to read:
+ ops::Add<Self, Output = Self>
+ ops::Sub<Self, Output = Self>
+ ops::AddAssign
+ ops::SubAssign
+ ops::Mul<Self, Output = Self>
+ ops::MulAssign
+ ops::Div<Self, Output = Self>
+ ops::DivAssign
+ for<'a> ops::Add<&'a Self, Output = Self>
+ for<'a> ops::Sub<&'a Self, Output = Self>
+ for<'a> ops::AddAssign<&'a Self>
+ for<'a> ops::SubAssign<&'a Self>
+ for<'a> ops::Mul<&'a Self, Output = Self>
+ for<'a> ops::MulAssign<&'a Self>
+ for<'a> ops::Div<&'a Self, Output = Self>
+ for<'a> ops::DivAssign<&'a Self>
+ ops::Neg
src/primitives/field.rs
Outdated
| /// instead of calling this. | ||
| fn _mul(&self, other: &Self) -> Self; | ||
|
|
||
| /// Divides a value from `self`. This is a helper funcion for implementing the |
There was a problem hiding this comment.
Is this real English? If so awesome and TIL, I have, in the past, written "divides self by value" and wished I could have the operands in the other order.
There was a problem hiding this comment.
Heh, I think the English is a bit sketchy ... but as you say, if you swap the operands there isn't really a good way to phrase it.
src/primitives/field.rs
Outdated
| fn multiplicative_order(&self) -> usize { | ||
| for &ord in Self::MULTIPLICATIVE_ORDER_FACTORS { | ||
| if self.powi(ord) == Self::ONE { | ||
| return ord as usize; |
There was a problem hiding this comment.
Why is this cast ok? Or said another way, why are multiplicative order factors i64s but we return a usize?
There was a problem hiding this comment.
I think I should make the factors all be usizes.
There was a problem hiding this comment.
But all these casts are OK because in practice none of these values will ever exceed 32 bits (or even 16 bits, probably).
src/primitives/field.rs
Outdated
| } | ||
|
|
||
| macro_rules! impl_ops_for_fe { | ||
| (impl$(<$params1:tt>)? for $op:ident$(<$param:tt>)?) => { |
There was a problem hiding this comment.
I'm not understanding what params1 is for, it doesn't appear in any function except on the impl keyword. Also its not used in any of the macro call sites?
There was a problem hiding this comment.
I should probably drop it. It was going to be for if I could implement this generically on Fe32Ext<DEG> but then I couldn't figure out how to write a generic-over-DEG division algo so I couldn't do it.
src/primitives/gf32_ext.rs
Outdated
| //! | ||
| //! We support specifically the fields GF1024 and GF32768 (the extension | ||
| //! fields of degree 2 and 3, respectively), though we have tried to write | ||
| //! the code in such a way that more can be added if codes require thhem. |
There was a problem hiding this comment.
| //! the code in such a way that more can be added if codes require thhem. | |
| //! the code in such a way that more can be added if codes require them. |
src/primitives/gf32_ext.rs
Outdated
| #[derive(Copy, Clone, PartialEq, Eq, Hash)] | ||
| pub struct Fe32Ext<const DEG: usize> { | ||
| /// The polynomial representation of the element in "little-endian" order; | ||
| /// that is, the element is the sum inner[i] * EXT_ELEM^i. |
There was a problem hiding this comment.
Square brackets need escaping like you do in other places.
There was a problem hiding this comment.
3 instances in the PR, find with cargo rustdoc --all-features -- --document-private-items
There was a problem hiding this comment.
Note please, before you change the PR, I make a further contradictory comment below.
src/primitives/checksum.rs
Outdated
| const WIDTH: usize = mem::size_of::<Self>() * 8 / 5; | ||
|
|
||
| /// Takes an iterator of `u8`s (or [`Fe32`]s converted to `u8`s) and packs | ||
| /// them into a Self. |
There was a problem hiding this comment.
nit, since the rest of the PR is so clean, lets use Self here.
src/primitives/checksum.rs
Outdated
| /// # Panics | ||
| /// | ||
| /// If the iterator yields more items than can fit into the bit-packed | ||
| /// type, will panic. |
There was a problem hiding this comment.
Should this be "may panic" since its on a trait and its up to the implementor?
src/primitives/gf32_ext.rs
Outdated
|
|
||
| /// The element zeta such that the extension field is defined as GF32\[zeta\]. | ||
| /// | ||
| /// Alternately, the image of x in the mapping GF32\[x\]/p(x) -> the field |
There was a problem hiding this comment.
nit: The escapes make it pretty noisy in the source code, perhaps we just put backtics around the whole expression?
/// Alternately, the image of x in the mapping `GF32[x]/p(x)` -> the field
(I built the docs and looked at it, looks ok in HTML.)
|
Meant to mention before, I found the API files very useful when reviewing. |
6c386ab to
02282fa
Compare
|
Addressed all comments. |
|
@clarkmoody what are next steps for this PR? |
|
I rekon we can merge this, its been open for a while now. @clarkmoody speak now or forever hold your peace :) |
|
It's a nontrivial change and unlike rust-bitcoin, I don't have a mandate to steer this crate (and actually even Github won't let me because you're not an approved approver), so I think we've gotta wait for Clark. |
|
Fair. |
|
Hi @clarkmoody, is there anything we can do to make reviewing this easier for you? I got a message out of band from FROST devs chasing error correction. I realize this is a massive PR and not at all easy to review. cc @nickfarrow |
| // any sort of `eval`, but you can manually check the output works. | ||
| let _s = PrintImpl::<Fe1024>::new( | ||
| "Bech32", | ||
| &[Fe32::A, Fe32::K, Fe32::_5, Fe32::_4, Fe32::A, Fe32::J], |
There was a problem hiding this comment.
Can we pass &unpacked_poly here directly, to avoid duplication/confusion?
There was a problem hiding this comment.
I'll try but IIRC there was some type confusion that prevented me from doing so
There was a problem hiding this comment.
Oh, I see, you mean to take the unpacked_poly computation from the unit test and put it in the doctest, so that the only magic constants that appear clearly came from the BIP. Sure.
|
This is some real Big Brain stuff! I've pointed out some minor things here and there. I apologize for going AWOL for so long. |
|
Let me open a PR to get CI working then I'll rebase this and address your comments. In the last couple months there has been a bunch of breakage in check-api and even rustc itself. |
I want to use const generics and I need 1.56 to do it. The rest of the rust-bitcoin ecosystem has moved to 1.56.1.
This new trait covers a larger matrix of ops, and implements them all with a single macro. Will allow us to introduce new fields (in particular, extension fields of GF32) in a future commit with more consistent/less boilerplate heavy implementations of basic arithmetic. We run the API checker in this commit so you can see that the API changes are strictly additive and only add missing op implementations.
Again, strictly adding API surface, not removing anything.
02282fa to
b977a7e
Compare
|
Rebased and addressed all nits. |
This introduces a type `Polynomial` which wraps a vector of field elements which it treats as the coefficients of a polynomial. It exposes only an ad-hoc set of functionality needed for error correction and is not intended to be a general-purpose polynomial type, so it is not exposed in the public API. Because it is backed by a `Vec` the type and its module are only available when the alloc feature is available.
Adds a couple elements to the API. Note that this *is* a breaking change because we are adding a method to the `PackedFe32` trait, which is not sealed, so any downstream implementors will be broken.
For the most part, BCH codes used in the ecosystem are defined as generator polynomials over GF32 and a target residue polynomial, and the remaining code parameters are not specified, or are only specified indirectly. It is difficult for non-experts to compute or even validate parameters such as the length of the code or the shifted+packed generator polynomials. It will be even more difficult in the sequel when we extend the Checksum trait to also cover error-correction parameters (some of which will depend on our particular choice of representation for GF1024 elements, which is not canonical and differs between different documents). So we introduce an object `PrintImpl` and a unit test and doctest demonstrating its use, which will generate all of the needed parameters and output a block of Rust code.
b977a7e to
caefc44
Compare
|
Thanks @clarkmoody, way to go. |
|
I'm not going to re-review this, I don't think a shallow re-ack from me adds much value. |
This PR does a couple things:
impl Checksumblock for codes which can be corrected using a quadratic or cubic field extension. This will hopefully provide some context for people not super familiar with BCH code about where these magic numbers come from.We also add unit tests that produce the parameters for codex32 and the descriptor checksum. A later PR will introduce more parameters which will be needed for error correction.