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