ark_models_ext/
transmute.rs1use ark_ec::{short_weierstrass as sw, twisted_edwards as te, CurveConfig};
4use core::mem::{align_of, size_of};
5
6pub trait CompatibleConfig<T>: CurveConfig
19where
20 T: CurveConfig<BaseField = Self::BaseField, ScalarField = Self::ScalarField>,
21{
22}
23
24pub trait TransmuteFrom<T>: Sized {
26 fn transmute_from(t: T) -> Self;
27}
28
29pub trait TransmuteInto<U>: Sized {
31 fn transmute_into(self) -> U;
32}
33
34impl<T, U: TransmuteFrom<T>> TransmuteInto<U> for T {
35 fn transmute_into(self) -> U {
36 U::transmute_from(self)
37 }
38}
39
40pub trait TransmuteRef<T: ?Sized> {
42 fn transmute_ref(&self) -> &T;
43}
44
45const fn assert_layout_compatible<S, D>() {
47 assert!(size_of::<S>() == size_of::<D>());
48 assert!(align_of::<S>() == align_of::<D>());
49}
50
51fn transmute_value<S, D>(src: S) -> D {
53 const { assert_layout_compatible::<S, D>() }
54 let src = core::mem::ManuallyDrop::new(src);
55 unsafe { core::ptr::read(&*src as *const S as *const D) }
56}
57
58fn transmute_ref<S, D>(src: &S) -> &D {
60 const { assert_layout_compatible::<S, D>() }
61 unsafe { &*(src as *const S as *const D) }
62}
63
64fn transmute_slice<S, D>(src: &[S]) -> &[D] {
66 const { assert_layout_compatible::<S, D>() }
67 unsafe { core::slice::from_raw_parts(src.as_ptr() as *const D, src.len()) }
68}
69
70impl<S, D> TransmuteFrom<te::Projective<S>> for te::Projective<D>
77where
78 D: te::TECurveConfig + CompatibleConfig<S>,
79 S: te::TECurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
80{
81 fn transmute_from(t: te::Projective<S>) -> Self {
82 transmute_value(t)
83 }
84}
85
86impl<S, D> TransmuteFrom<te::Affine<S>> for te::Affine<D>
87where
88 D: te::TECurveConfig + CompatibleConfig<S>,
89 S: te::TECurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
90{
91 fn transmute_from(t: te::Affine<S>) -> Self {
92 transmute_value(t)
93 }
94}
95
96impl<S, D> TransmuteFrom<sw::Projective<S>> for sw::Projective<D>
97where
98 D: sw::SWCurveConfig + CompatibleConfig<S>,
99 S: sw::SWCurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
100{
101 fn transmute_from(t: sw::Projective<S>) -> Self {
102 transmute_value(t)
103 }
104}
105
106impl<S, D> TransmuteFrom<sw::Affine<S>> for sw::Affine<D>
107where
108 D: sw::SWCurveConfig + CompatibleConfig<S>,
109 S: sw::SWCurveConfig<
110 BaseField = D::BaseField,
111 ScalarField = D::ScalarField,
112 ZeroFlag = D::ZeroFlag,
113 >,
114{
115 fn transmute_from(t: sw::Affine<S>) -> Self {
116 transmute_value(t)
117 }
118}
119
120impl<S, D> TransmuteRef<te::Projective<D>> for te::Projective<S>
127where
128 S: te::TECurveConfig + CompatibleConfig<D>,
129 D: te::TECurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
130{
131 fn transmute_ref(&self) -> &te::Projective<D> {
132 transmute_ref(self)
133 }
134}
135
136impl<S, D> TransmuteRef<sw::Projective<D>> for sw::Projective<S>
137where
138 S: sw::SWCurveConfig + CompatibleConfig<D>,
139 D: sw::SWCurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
140{
141 fn transmute_ref(&self) -> &sw::Projective<D> {
142 transmute_ref(self)
143 }
144}
145
146impl<S, D> TransmuteRef<sw::Affine<D>> for sw::Affine<S>
147where
148 S: sw::SWCurveConfig + CompatibleConfig<D>,
149 D: sw::SWCurveConfig<
150 BaseField = S::BaseField,
151 ScalarField = S::ScalarField,
152 ZeroFlag = S::ZeroFlag,
153 >,
154{
155 fn transmute_ref(&self) -> &sw::Affine<D> {
156 transmute_ref(self)
157 }
158}
159
160impl<S, D> TransmuteRef<te::Affine<D>> for te::Affine<S>
161where
162 S: te::TECurveConfig + CompatibleConfig<D>,
163 D: te::TECurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
164{
165 fn transmute_ref(&self) -> &te::Affine<D> {
166 transmute_ref(self)
167 }
168}
169
170impl<S, D> TransmuteRef<[te::Affine<D>]> for [te::Affine<S>]
173where
174 S: te::TECurveConfig + CompatibleConfig<D>,
175 D: te::TECurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
176{
177 fn transmute_ref(&self) -> &[te::Affine<D>] {
178 transmute_slice(self)
179 }
180}
181
182impl<S, D> TransmuteRef<[sw::Affine<D>]> for [sw::Affine<S>]
183where
184 S: sw::SWCurveConfig + CompatibleConfig<D>,
185 D: sw::SWCurveConfig<
186 BaseField = S::BaseField,
187 ScalarField = S::ScalarField,
188 ZeroFlag = S::ZeroFlag,
189 >,
190{
191 fn transmute_ref(&self) -> &[sw::Affine<D>] {
192 transmute_slice(self)
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199 use ark_std::{test_rng, UniformRand};
200
201 fn rand_point<T: UniformRand>() -> T {
202 T::rand(&mut test_rng())
203 }
204
205 fn rand_points<T: UniformRand>(n: usize) -> Vec<T> {
206 let rng = &mut test_rng();
207 (0..n).map(|_| T::rand(rng)).collect()
208 }
209
210 mod sw_test {
214 use super::*;
215 use ark_bls12_381::g1::Config as ArkG1Config;
216
217 #[derive(Clone, Copy)]
218 struct ExtConfig;
219
220 impl CurveConfig for ExtConfig {
221 type BaseField = <ArkG1Config as CurveConfig>::BaseField;
222 type ScalarField = <ArkG1Config as CurveConfig>::ScalarField;
223 const COFACTOR: &'static [u64] = <ArkG1Config as CurveConfig>::COFACTOR;
224 const COFACTOR_INV: Self::ScalarField = <ArkG1Config as CurveConfig>::COFACTOR_INV;
225 }
226
227 impl sw::SWCurveConfig for ExtConfig {
228 type ZeroFlag = <ArkG1Config as sw::SWCurveConfig>::ZeroFlag;
229
230 const COEFF_A: Self::BaseField = <ArkG1Config as sw::SWCurveConfig>::COEFF_A;
231 const COEFF_B: Self::BaseField = <ArkG1Config as sw::SWCurveConfig>::COEFF_B;
232 const GENERATOR: sw::Affine<Self> = sw::Affine::new_unchecked(
233 <ArkG1Config as sw::SWCurveConfig>::GENERATOR.x,
234 <ArkG1Config as sw::SWCurveConfig>::GENERATOR.y,
235 );
236 }
237
238 impl CompatibleConfig<ArkG1Config> for ExtConfig {}
239
240 #[test]
241 fn sw_affine_roundtrip() {
242 let point: sw::Affine<ArkG1Config> = rand_point();
243 let ext: sw::Affine<ExtConfig> = point.transmute_into();
244 let back: &sw::Affine<ArkG1Config> = ext.transmute_ref();
245 assert_eq!(*back, point);
246 }
247
248 #[test]
249 fn sw_projective_roundtrip() {
250 let point: sw::Projective<ArkG1Config> = rand_point();
251 let ext: sw::Projective<ExtConfig> = point.transmute_into();
252 let back: &sw::Projective<ArkG1Config> = ext.transmute_ref();
253 assert_eq!(*back, point);
254 }
255
256 #[test]
257 fn sw_affine_slice_roundtrip() {
258 let ark_points: Vec<sw::Affine<ArkG1Config>> = rand_points(5);
259 let ext_points: Vec<sw::Affine<ExtConfig>> = ark_points
260 .iter()
261 .copied()
262 .map(|p| p.transmute_into())
263 .collect();
264 let back: &[sw::Affine<ArkG1Config>] = ext_points.as_slice().transmute_ref();
265 assert_eq!(back, ark_points.as_slice());
266 }
267 }
268
269 mod te_test {
270 use super::*;
271 use ark_ed25519::EdwardsConfig as ArkTeConfig;
272
273 #[derive(Clone, Copy)]
274 struct ExtConfig;
275
276 impl CurveConfig for ExtConfig {
277 type BaseField = <ArkTeConfig as CurveConfig>::BaseField;
278 type ScalarField = <ArkTeConfig as CurveConfig>::ScalarField;
279 const COFACTOR: &'static [u64] = <ArkTeConfig as CurveConfig>::COFACTOR;
280 const COFACTOR_INV: Self::ScalarField = <ArkTeConfig as CurveConfig>::COFACTOR_INV;
281 }
282
283 impl te::TECurveConfig for ExtConfig {
284 const COEFF_A: Self::BaseField = <ArkTeConfig as te::TECurveConfig>::COEFF_A;
285 const COEFF_D: Self::BaseField = <ArkTeConfig as te::TECurveConfig>::COEFF_D;
286 const GENERATOR: te::Affine<Self> = te::Affine::new_unchecked(
287 <ArkTeConfig as te::TECurveConfig>::GENERATOR.x,
288 <ArkTeConfig as te::TECurveConfig>::GENERATOR.y,
289 );
290 type MontCurveConfig = ArkTeConfig;
291 }
292
293 impl CompatibleConfig<ArkTeConfig> for ExtConfig {}
294
295 #[test]
296 fn te_affine_roundtrip() {
297 let point: te::Affine<ArkTeConfig> = rand_point();
298 let ext: te::Affine<ExtConfig> = point.transmute_into();
299 let back: &te::Affine<ArkTeConfig> = ext.transmute_ref();
300 assert_eq!(*back, point);
301 }
302
303 #[test]
304 fn te_projective_roundtrip() {
305 let point: te::Projective<ArkTeConfig> = rand_point();
306 let ext: te::Projective<ExtConfig> = point.transmute_into();
307 let back: &te::Projective<ArkTeConfig> = ext.transmute_ref();
308 assert_eq!(*back, point);
309 }
310
311 #[test]
312 fn te_affine_slice_roundtrip() {
313 let ark_points: Vec<te::Affine<ArkTeConfig>> = rand_points(5);
314 let ext_points: Vec<te::Affine<ExtConfig>> = ark_points
315 .iter()
316 .copied()
317 .map(|p| p.transmute_into())
318 .collect();
319 let back: &[te::Affine<ArkTeConfig>] = ext_points.as_slice().transmute_ref();
320 assert_eq!(back, ark_points.as_slice());
321 }
322 }
323}