Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 35 additions & 38 deletions elliptic-curve/src/point/non_identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,39 @@ where
}
}

impl<P> NonIdentity<P> {
/// Transform array reference containing [`NonIdentity`] points to an array reference to the
/// inner point type.
pub fn cast_array_as_inner<const N: usize>(points: &[Self; N]) -> &[P; N] {
// Ensure casting is safe.
// This always succeeds because `NonIdentity` is `repr(transparent)`.
debug_assert_eq!(size_of::<P>(), size_of::<NonIdentity<P>>());
debug_assert_eq!(align_of::<P>(), align_of::<NonIdentity<P>>());

// SAFETY: `NonIdentity` is a `repr(transparent)` newtype for `P` so it's safe to cast to
// the inner `P` type.
#[allow(unsafe_code)]
unsafe {
&*points.as_ptr().cast()
}
}

/// Transform slice containing [`NonIdentity`] points to a slice of the inner point type.
pub fn cast_slice_as_inner(points: &[Self]) -> &[P] {
// Ensure casting is safe.
// This always succeeds because `NonIdentity` is `repr(transparent)`.
debug_assert_eq!(size_of::<P>(), size_of::<NonIdentity<P>>());
debug_assert_eq!(align_of::<P>(), align_of::<NonIdentity<P>>());

// SAFETY: `NonIdentity` is a `repr(transparent)` newtype for `P` so it's safe to cast to
// the inner `P` type.
#[allow(unsafe_code)]
unsafe {
&*(points as *const [NonIdentity<P>] as *const [P])
}
}
}

impl<P: Copy> NonIdentity<P> {
/// Return wrapped point.
pub fn to_point(self) -> P {
Expand Down Expand Up @@ -114,26 +147,8 @@ where
type Output = [NonIdentity<P::AffineRepr>; N];

fn batch_normalize(points: &[Self; N]) -> [NonIdentity<P::AffineRepr>; N] {
// Ensure casting is safe.
// This always succeeds because `NonIdentity` is `repr(transparent)`.
debug_assert_eq!(size_of::<P>(), size_of::<NonIdentity<P>>());
debug_assert_eq!(align_of::<P>(), align_of::<NonIdentity<P>>());

#[allow(unsafe_code)]
// SAFETY: `NonIdentity` is `repr(transparent)`.
let points: &[P; N] = unsafe { &*points.as_ptr().cast() };
let points = Self::cast_array_as_inner::<N>(points);
let affine_points = <P as BatchNormalize<_>>::batch_normalize(points);

// Ensure `array::map()` can be optimized to a `memcpy`.
debug_assert_eq!(
size_of::<P::AffineRepr>(),
size_of::<NonIdentity<P::AffineRepr>>()
);
debug_assert_eq!(
align_of::<P::AffineRepr>(),
align_of::<NonIdentity<P::AffineRepr>>()
);
Comment on lines -127 to -135

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed these because these properties should always hold true for a repr(transparent) newtype


affine_points.map(|point| NonIdentity { point })
}
}
Expand All @@ -146,26 +161,8 @@ where
type Output = Vec<NonIdentity<P::AffineRepr>>;

fn batch_normalize(points: &[Self]) -> Vec<NonIdentity<P::AffineRepr>> {
// Ensure casting is safe.
// This always succeeds because `NonIdentity` is `repr(transparent)`.
debug_assert_eq!(size_of::<P>(), size_of::<NonIdentity<P>>());
debug_assert_eq!(align_of::<P>(), align_of::<NonIdentity<P>>());

#[allow(unsafe_code)]
// SAFETY: `NonIdentity` is `repr(transparent)`.
let points: &[P] = unsafe { &*(points as *const [NonIdentity<P>] as *const [P]) };
let points = Self::cast_slice_as_inner(points);
let affine_points = <P as BatchNormalize<_>>::batch_normalize(points);

// Ensure `into_iter()` + `collect()` can be optimized away.
debug_assert_eq!(
size_of::<P::AffineRepr>(),
size_of::<NonIdentity<P::AffineRepr>>()
);
debug_assert_eq!(
align_of::<P::AffineRepr>(),
align_of::<NonIdentity<P::AffineRepr>>()
);

affine_points
.into_iter()
.map(|point| NonIdentity { point })
Expand Down