@@ -22,7 +22,7 @@ use crate::{BatchNormalize, CurveArithmetic, NonZeroScalar, Scalar};
22
22
/// In the context of ECC, it's useful for ensuring that certain arithmetic
23
23
/// cannot result in the identity point.
24
24
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
25
- #[ repr( transparent) ]
25
+ #[ repr( transparent) ] // SAFETY: needed for `unsafe` safety invariants below
26
26
pub struct NonIdentity < P > {
27
27
point : P ,
28
28
}
51
51
}
52
52
}
53
53
54
+ impl < P > NonIdentity < P > {
55
+ /// Transform array reference containing [`NonIdentity`] points to an array reference to the
56
+ /// inner point type.
57
+ pub fn cast_array_as_inner < const N : usize > ( points : & [ Self ; N ] ) -> & [ P ; N ] {
58
+ // SAFETY: `NonIdentity` is a `repr(transparent)` newtype for `P` so it's safe to cast to
59
+ // the inner `P` type.
60
+ #[ allow( unsafe_code) ]
61
+ unsafe {
62
+ & * points. as_ptr ( ) . cast ( )
63
+ }
64
+ }
65
+
66
+ /// Transform slice containing [`NonIdentity`] points to a slice of the inner point type.
67
+ pub fn cast_slice_as_inner ( points : & [ Self ] ) -> & [ P ] {
68
+ // SAFETY: `NonIdentity` is a `repr(transparent)` newtype for `P` so it's safe to cast to
69
+ // the inner `P` type.
70
+ #[ allow( unsafe_code) ]
71
+ unsafe {
72
+ & * ( points as * const [ NonIdentity < P > ] as * const [ P ] )
73
+ }
74
+ }
75
+ }
76
+
54
77
impl < P : Copy > NonIdentity < P > {
55
78
/// Return wrapped point.
56
79
pub fn to_point ( self ) -> P {
@@ -114,26 +137,8 @@ where
114
137
type Output = [ NonIdentity < P :: AffineRepr > ; N ] ;
115
138
116
139
fn batch_normalize ( points : & [ Self ; N ] ) -> [ NonIdentity < P :: AffineRepr > ; N ] {
117
- // Ensure casting is safe.
118
- // This always succeeds because `NonIdentity` is `repr(transparent)`.
119
- debug_assert_eq ! ( size_of:: <P >( ) , size_of:: <NonIdentity <P >>( ) ) ;
120
- debug_assert_eq ! ( align_of:: <P >( ) , align_of:: <NonIdentity <P >>( ) ) ;
121
-
122
- #[ allow( unsafe_code) ]
123
- // SAFETY: `NonIdentity` is `repr(transparent)`.
124
- let points: & [ P ; N ] = unsafe { & * points. as_ptr ( ) . cast ( ) } ;
140
+ let points = Self :: cast_array_as_inner :: < N > ( points) ;
125
141
let affine_points = <P as BatchNormalize < _ > >:: batch_normalize ( points) ;
126
-
127
- // Ensure `array::map()` can be optimized to a `memcpy`.
128
- debug_assert_eq ! (
129
- size_of:: <P :: AffineRepr >( ) ,
130
- size_of:: <NonIdentity <P :: AffineRepr >>( )
131
- ) ;
132
- debug_assert_eq ! (
133
- align_of:: <P :: AffineRepr >( ) ,
134
- align_of:: <NonIdentity <P :: AffineRepr >>( )
135
- ) ;
136
-
137
142
affine_points. map ( |point| NonIdentity { point } )
138
143
}
139
144
}
@@ -146,26 +151,8 @@ where
146
151
type Output = Vec < NonIdentity < P :: AffineRepr > > ;
147
152
148
153
fn batch_normalize ( points : & [ Self ] ) -> Vec < NonIdentity < P :: AffineRepr > > {
149
- // Ensure casting is safe.
150
- // This always succeeds because `NonIdentity` is `repr(transparent)`.
151
- debug_assert_eq ! ( size_of:: <P >( ) , size_of:: <NonIdentity <P >>( ) ) ;
152
- debug_assert_eq ! ( align_of:: <P >( ) , align_of:: <NonIdentity <P >>( ) ) ;
153
-
154
- #[ allow( unsafe_code) ]
155
- // SAFETY: `NonIdentity` is `repr(transparent)`.
156
- let points: & [ P ] = unsafe { & * ( points as * const [ NonIdentity < P > ] as * const [ P ] ) } ;
154
+ let points = Self :: cast_slice_as_inner ( points) ;
157
155
let affine_points = <P as BatchNormalize < _ > >:: batch_normalize ( points) ;
158
-
159
- // Ensure `into_iter()` + `collect()` can be optimized away.
160
- debug_assert_eq ! (
161
- size_of:: <P :: AffineRepr >( ) ,
162
- size_of:: <NonIdentity <P :: AffineRepr >>( )
163
- ) ;
164
- debug_assert_eq ! (
165
- align_of:: <P :: AffineRepr >( ) ,
166
- align_of:: <NonIdentity <P :: AffineRepr >>( )
167
- ) ;
168
-
169
156
affine_points
170
157
. into_iter ( )
171
158
. map ( |point| NonIdentity { point } )
0 commit comments