elliptic-curves
elliptic-curves copied to clipboard
p256: Allow converting affine points to coordinates and back
This adds a trait AffineCoordinates with two methods (from_coordinates and to_coordinates) to convert field element coordinates to points and back, checking that the coordinates are on the curve. Internal conversions now use this trait, and the trait is exposed publicly if the expose-field flag is set.
Also re-exports the two curve constants if the expose-field flag is set.
These two changes would allow for a full Elligator Squared implementation (#540) entirely outside of the p256 crate.
I strongly disagree with exposing from_coordinates_unchecked on principle; it's dangerous for security. If unchecked construction is to be permitted, I think it should only be from byte encodings (which are less likely to be accidentally manipulated).
Checked construction is a more reasonable thing to expose in a public API. I still dislike it, and would prefer it be segmented in some way so downstream users only reach for it if they really need it (as cryptographic protocols that depend on the internal coordinate details of elliptic curves are devilishly tricky to make safe in generic contexts, and really should just be implemented concretely by the concrete curve implementations, or have a different safer interface).
I agree that this is definitely hazmat and I’d be happy to modify this to check that the point is indeed on the curve, but I should note that this functionality is entirely possible with the existing public API:
fn coordinates_to_point(x: &FieldElement, y: &FieldElement) -> AffinePoint {
let enc = EncodedPoint::from_affine_coordinates(&x.to_bytes(), &y.to_bytes(), false);
AffinePoint::from_encoded_point(&enc).unwrap()
}
fn point_to_coordinates(q: AffinePoint) -> (FieldElement, FieldElement) {
let enc = q.to_encoded_point(false);
let x = FieldElement::from_bytes(enc.x().unwrap()).unwrap();
let y = FieldElement::from_bytes(enc.y().unwrap()).unwrap();
(x, y)
}
This is what I’m currently using to implement Elligator Squared outside of the p256 crate and it works (at the expense of being slow and an aesthetic bummer).
I’m sympathetic to wanting to keep the hazmat factor of the public API low (and lord knows smashing together EC points from rando bigints has a history), but there definitely exists a category of EC algorithm which a) cannot be implemented without point/FE conversion and b) does not clear the cost/benefit bar to be included into these crates and maintained in perpetuity.
Elligator Squared is a good example of this. It’s a very uncommon use case, it’s not at all standardized, and very little of the algorithm itself is generic between curves. I have a PR with a full in-library implementation of Elligator Squared for p256 with a safe API (#540), but I’d be the first to admit that it’s not a PR worth merging.
I just pushed a change to check the coordinates for validity. Conditionally exposing this functionality requires extracting it as a trait, so it’s a little more verbose.
@codahale this issue for adding coordinate access APIs to the group crate is potentially relevant here: https://github.com/zkcrypto/group/issues/30
I think we'll go with whatever prospective solution there is for https://github.com/zkcrypto/group/issues/30