-
Notifications
You must be signed in to change notification settings - Fork 62
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
Extended Galois field #38
Conversation
@drskalman Thanks very much for the work! Since @rphmeier 's PR was merged into master before your PR, could you sync the branch from master to resolve the conflicts? Thanks! |
Thanks for looking into this. Sure I can. I'm a rust newbie and I wasn't expecting merge without major change. So it was there more for seeking improvement advice rather than merge. But I'll do that. I'll close this and open a new one after rebase. It would be nice if you can add @rphmeier also as reviewer to the new PR. |
I am not sure if I have taken a look close enough to give proper advice, I do have some thoughts on the implementations however. I have not looked closely enough, so please do correct me if I got the wrong impression.
I can't add people as "reviewer" properly unless I add them as collaborator to this project, at which point I'd rather move this into an organisation project. But I'll mention him in the new PR. |
src/galois_ext.rs
Outdated
} | ||
|
||
pub fn from(original_rep_polynom: &Polynom) -> ExtendedFieldElement { | ||
|
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.
extraneous whitespace -- also this is better as a From
implementation
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.
actually, I can see that there is also a From
implementation and that it is equivalent to this function except for the fact that one reduces and one doesn't. What is the correct behavior? I would write to reduce to err on the side of caution.
src/galois_ext.rs
Outdated
@@ -0,0 +1,92 @@ | |||
use ::poly::Polynom; | |||
use poly_math::*; |
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.
better not to use glob imports
src/galois_ext.rs
Outdated
pub fn inverse(self: &Self) -> ExtendedFieldElement { | ||
if !self.is_zero() { | ||
let (gcd, x, _) = self.rep_polynom.egcd(&EXT_POLY!()); | ||
//we still need to normilze it by divinig by the gcd |
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.
quite a lot of typos in this function. it might also be better to document the fact that inverting zero panics
src/galois_ext.rs
Outdated
} | ||
|
||
|
||
pub fn is_zero(self: &Self)-> bool { |
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.
self: &Self
equivalent to &self
This is a legitimate concern, but I think as long as we abstract everything sufficiently via traits it shouldn't end up having non-local effects. I'm pushing a few changes:
|
src/macros.rs
Outdated
} | ||
} | ||
|
||
macro_rules! EXT_POLY { |
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.
what is this for?
src/macros.rs
Outdated
macro_rules! uncheck_mut { | ||
($array:ident[$index:expr]) => { | ||
* if cfg!(feature = "unsafe_indexing") { | ||
unsafe { |
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 would recommend removing the unsafe indexing entirely. rustc is good at eliding bounds checks where possible
src/poly.rs
Outdated
*x = 0; | ||
} | ||
} else if new_len < old_len { | ||
self.dirty = true; |
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 don't see anywhere where the dirty
flag is getting set to false
again. Why not just ignore the bits further than length
?
src/poly.rs
Outdated
} | ||
|
||
#[inline] | ||
pub fn set_length(&mut self, new_len: 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.
what should happen if new_len > POLYNOMIAL_MAX_LENGTH
?
src/poly.rs
Outdated
|
||
#[inline] | ||
pub fn reverse(mut self) -> Self { | ||
(*self).reverse(); |
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.
doesn't this need to take into account length?
c1c98f5
to
2791287
Compare
2791287
to
cc374ef
Compare
1 similar comment
Codecov Report
@@ Coverage Diff @@
## master #38 +/- ##
==========================================
- Coverage 96.77% 96.35% -0.42%
==========================================
Files 7 8 +1
Lines 2479 2771 +292
==========================================
+ Hits 2399 2670 +271
- Misses 80 101 +21
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #38 +/- ##
==========================================
- Coverage 96.77% 95.86% -0.91%
==========================================
Files 7 7
Lines 2479 2612 +133
==========================================
+ Hits 2399 2504 +105
- Misses 80 108 +28
Continue to review full report at Codecov.
|
dec113d
to
6677c18
Compare
Just want to confirm something in case I'm being stupid, so the .sage file is only for testing the formulas manually, right? (Mainly want to ensure no static look up tables are/will be generated by sage/non-Rust code) |
The sage formula is used to generate the irreducible polynomial we use as a modulus for GF(2^16), but not at build time. In the future we will probably drop the polynomial logic and extend with another table of size 256, generated at build time. |
Ok, I think this should be ready for review now. I managed to get rid of the arbitrary length polynomials by porting over a couple specialized cases of polynomial division and the extended euclidean algorithm to the |
Thanks very much @drskalman @rphmeier ! I'll try to get to reviewing it in a day or so, next 3 days are especially busy for me, so apologies if I don't end up reviewing it in time as suggested. |
src/galois_16.rs
Outdated
} | ||
|
||
// either self is zero polynomial or is equivalent to 0 | ||
panic!("Cannot invert 0"); |
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.
Personally I feel it would be nicer to move the panic!(...)
to top the top of the code, or change this function into if ... else ..
branching, as these two options feel easier for audit and analysis.
Just to be more specific, moving it to top would be
if self.zero(...) {
panic!("Cannot invert 0");
}
// first step of extended euclidean algorithm.
...
changing into if ... else ...
branch would be
if self.zero(...) {
panic!("Cannot invert 0");
} else {
// first step of extended euclidean algorithm.
...
}
Largely my habit though, the main rationale would be regardless of function size, the panic!()
s would always be visible at top of function, or at the top of one of the branches.
Seems best to also include tests for I'll come back later to look over the remaining portion. |
The tests look good, I might add more tests later on just to safe guard future changes, but I feel the coverage should be solid enough for now. Thanks for the work again @drskalman @rphmeier |
More tests are always a bonus! |
|
It is my first ever rust code for public consumption so it probably needs lots of improvement :-)
My goal at this stage was to write something fast so I can make the reed-solomon codes work for GF((2^8)^n) and then improve it afterward. So efficiency, etc wasn't on my mind at this stage.
Although it works for any extension degree n, the tests are written for GF((2^8)^2) extended by x^2 + a*x + a^7 (where a is the generator of GF(2^8) field used in this code).