-
Couldn't load subscription status.
- Fork 563
Add expose-field to expose FieldElement
#816
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
base: main
Are you sure you want to change the base?
Conversation
The underlying field elements are unsafe for public consumption as they have undefined arithmetic after a certain amount of uses. This trait solves the problem as following: - Defining a `ff::Field` wrapper which reduces after _every operation_ - Defining a bespoke `LazyField` trait which tracks consumed capacity using `typenum` - Definining a wrapper so any existing `ff::Field` may satisfy `LazyField` (actually allowing the `LazyField` trait to be considered for usage) - Defining a marker trait for any lazy field with a certain amount of capacity, so code generic to the field may still reduce how often they perform modular reductions - Implementing `LazyField` for `FieldElement`
|
cc @tarcieri My next step would be to work on tests if this is eligible for consideration. In reality, the lazy traits should be upstreamed somewhere, but it's probably best to resolve their API first here (with context of usage). Unfortunately, due to the 32-bit backends, we only get three additions guaranteed (not eight). That may be without issue, as curve formula generally do an add and then a multiply (so only requiring a single addition), but the gap between 32-bit and 64-bit platforms is still notable. Help is requested regarding the implementation of type X = Y;
fn z() -> Y;where Also, I'm unsure why the CI is failing. It's expecting a |
…`LazyField` trait Adds a simple wrapper which stops dependents from accessing the underlying type.
All always return reduced outputs for all four backends present within curve25519-dalek. This may be an unnecessary design choice of the backends, offering potential future improvements, yet it's one we can take advantage of here.
|
Maybe just call it @kayabaNerve the only build error I'm seeing is:
Can't you just bound appropriately, e.g. |
|
I didn't realize The library compiles for me, with I'll take a look at the |
|
And somehow, CI passes now. Amazing. I have no idea what's different. Renamed to |
|
Fun. The latest commit edited the README and caused a spurious test failure... I'll revisit the bounds on 32-bit platforms. We may only get a single addition :/ |
| #[test] | ||
| fn lazy_add_then_mul() { | ||
| use crate::hazmat::FieldElement; | ||
| use core::marker::PhantomData; | ||
| use ff::Field; | ||
| use rand_core::{OsRng, TryRngCore}; | ||
|
|
||
| let mut rng = OsRng.unwrap_err(); | ||
|
|
||
| let a = FieldElement::random(&mut rng); | ||
| let b = FieldElement::random(&mut rng); | ||
| let c = FieldElement::random(&mut rng); | ||
| let d = FieldElement::random(&mut rng); | ||
| let e = FieldElement::random(&mut rng); | ||
| let f = FieldElement::random(&mut rng); | ||
| let expected = (a + b + c) * (d + e + f); | ||
|
|
||
| assert_eq!( | ||
| LazyField::add(a, &b) | ||
| .add(&c) | ||
| .mul(&LazyField::add(d, &e).add(&f)), | ||
| expected | ||
| ); | ||
| assert_eq!(add_triple_then_mul(a, b, c, d, e, f), expected); | ||
|
|
||
| let a = EagerField(a, PhantomData::<typenum::U1>); | ||
| let b = EagerField(b, PhantomData::<typenum::U1>); | ||
| let c = EagerField(c, PhantomData::<typenum::U1>); | ||
| let d = EagerField(d, PhantomData::<typenum::U1>); | ||
| let e = EagerField(e, PhantomData::<typenum::U1>); | ||
| let f = EagerField(f, PhantomData::<typenum::U1>); | ||
|
|
||
| assert_eq!( | ||
| LazyField::add(a, &b) | ||
| .add(&c) | ||
| .mul(&LazyField::add(d, &e).add(&f)) | ||
| .0, | ||
| expected | ||
| ); | ||
| assert_eq!(add_triple_then_mul(a, b, c, d, e, f).0, expected); | ||
| } |
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.
If you used proptests for these, we could get the information needed to reproduce CI failures like: https://github.com/dalek-cryptography/curve25519-dalek/actions/runs/17444578081/job/49535734542?pr=816#step:8:205
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.
Will look to set that up next.
|
The docstring says the values are allowed to grow by up to |
|
Found it. I assumed |
Restores bound of `3` for 32-bit platforms.
The underlying field elements are unsafe for public consumption as they have undefined arithmetic after a certain amount of uses. This trait solves the problem as following:
ff::Fieldwrapper which reduces after every operationLazyFieldtrait which tracks consumed capacity usingtypenumff::Fieldmay satisfyLazyField(actually allowing theLazyFieldtrait to be considered for usage)LazyFieldforFieldElementSupersedes #787 if and only if this path is preferred. Resolves #389. This new type also could be used internally, ensuring there's no human-error in the existing uses of
FieldElement, yet that would be a much more intensive PR best left to later.