-
Notifications
You must be signed in to change notification settings - Fork 51
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
checksum: introduce PrintImpl
object that can compute various code properties
#180
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was a pleasure to review, the code is super clean. Code review only, no clue if the math is right :)
src/primitives/field.rs
Outdated
+ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this cast ok? Or said another way, why are multiplicative order factors i64
s but we return a usize
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I should make the factors all be usize
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//! 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Square brackets need escaping like you do in other places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 instances in the PR, find with cargo rustdoc --all-features -- --document-private-items
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note please, before you change the PR, I make a further contradictory comment below.
src/primitives/checksum.rs
Outdated
@@ -154,6 +319,18 @@ pub trait PackedFe32: Copy + PartialEq + Eq + ops::BitXor<Self, Output = Self> { | |||
/// The number of fe32s that can fit into the type; computed as floor(bitwidth / 5). | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 02282fa
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we pass &unpacked_poly
here directly, to avoid duplication/confusion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try but IIRC there was some type confusion that prevented me from doing so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK caefc44
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 Checksum
block 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.