use ark_ec::{short_weierstrass as sw, twisted_edwards as te, CurveConfig};
use core::mem::{align_of, size_of};
pub trait CompatibleConfig<T>: CurveConfig
where
T: CurveConfig<BaseField = Self::BaseField, ScalarField = Self::ScalarField>,
{
}
pub trait TransmuteFrom<T>: Sized {
fn transmute_from(t: T) -> Self;
}
pub trait TransmuteInto<U>: Sized {
fn transmute_into(self) -> U;
}
impl<T, U: TransmuteFrom<T>> TransmuteInto<U> for T {
fn transmute_into(self) -> U {
U::transmute_from(self)
}
}
pub trait TransmuteRef<T: ?Sized> {
fn transmute_ref(&self) -> &T;
}
const fn assert_layout_compatible<S, D>() {
assert!(size_of::<S>() == size_of::<D>());
assert!(align_of::<S>() == align_of::<D>());
}
fn transmute_value<S, D>(src: S) -> D {
const { assert_layout_compatible::<S, D>() }
let src = core::mem::ManuallyDrop::new(src);
unsafe { core::ptr::read(&*src as *const S as *const D) }
}
fn transmute_ref<S, D>(src: &S) -> &D {
const { assert_layout_compatible::<S, D>() }
unsafe { &*(src as *const S as *const D) }
}
fn transmute_slice<S, D>(src: &[S]) -> &[D] {
const { assert_layout_compatible::<S, D>() }
unsafe { core::slice::from_raw_parts(src.as_ptr() as *const D, src.len()) }
}
impl<S, D> TransmuteFrom<te::Projective<S>> for te::Projective<D>
where
D: te::TECurveConfig + CompatibleConfig<S>,
S: te::TECurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
{
fn transmute_from(t: te::Projective<S>) -> Self {
transmute_value(t)
}
}
impl<S, D> TransmuteFrom<te::Affine<S>> for te::Affine<D>
where
D: te::TECurveConfig + CompatibleConfig<S>,
S: te::TECurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
{
fn transmute_from(t: te::Affine<S>) -> Self {
transmute_value(t)
}
}
impl<S, D> TransmuteFrom<sw::Projective<S>> for sw::Projective<D>
where
D: sw::SWCurveConfig + CompatibleConfig<S>,
S: sw::SWCurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
{
fn transmute_from(t: sw::Projective<S>) -> Self {
transmute_value(t)
}
}
impl<S, D> TransmuteFrom<sw::Affine<S>> for sw::Affine<D>
where
D: sw::SWCurveConfig + CompatibleConfig<S>,
S: sw::SWCurveConfig<BaseField = D::BaseField, ScalarField = D::ScalarField>,
{
fn transmute_from(t: sw::Affine<S>) -> Self {
transmute_value(t)
}
}
impl<S, D> TransmuteRef<te::Projective<D>> for te::Projective<S>
where
S: te::TECurveConfig + CompatibleConfig<D>,
D: te::TECurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
{
fn transmute_ref(&self) -> &te::Projective<D> {
transmute_ref(self)
}
}
impl<S, D> TransmuteRef<sw::Projective<D>> for sw::Projective<S>
where
S: sw::SWCurveConfig + CompatibleConfig<D>,
D: sw::SWCurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
{
fn transmute_ref(&self) -> &sw::Projective<D> {
transmute_ref(self)
}
}
impl<S, D> TransmuteRef<sw::Affine<D>> for sw::Affine<S>
where
S: sw::SWCurveConfig + CompatibleConfig<D>,
D: sw::SWCurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
{
fn transmute_ref(&self) -> &sw::Affine<D> {
transmute_ref(self)
}
}
impl<S, D> TransmuteRef<te::Affine<D>> for te::Affine<S>
where
S: te::TECurveConfig + CompatibleConfig<D>,
D: te::TECurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
{
fn transmute_ref(&self) -> &te::Affine<D> {
transmute_ref(self)
}
}
impl<S, D> TransmuteRef<[te::Affine<D>]> for [te::Affine<S>]
where
S: te::TECurveConfig + CompatibleConfig<D>,
D: te::TECurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
{
fn transmute_ref(&self) -> &[te::Affine<D>] {
transmute_slice(self)
}
}
impl<S, D> TransmuteRef<[sw::Affine<D>]> for [sw::Affine<S>]
where
S: sw::SWCurveConfig + CompatibleConfig<D>,
D: sw::SWCurveConfig<BaseField = S::BaseField, ScalarField = S::ScalarField>,
{
fn transmute_ref(&self) -> &[sw::Affine<D>] {
transmute_slice(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use ark_std::{test_rng, UniformRand};
fn rand_point<T: UniformRand>() -> T {
T::rand(&mut test_rng())
}
fn rand_points<T: UniformRand>(n: usize) -> Vec<T> {
let rng = &mut test_rng();
(0..n).map(|_| T::rand(rng)).collect()
}
mod sw_test {
use super::*;
use ark_bls12_381::g1::Config as ArkG1Config;
#[derive(Clone, Copy)]
struct ExtConfig;
impl CurveConfig for ExtConfig {
type BaseField = <ArkG1Config as CurveConfig>::BaseField;
type ScalarField = <ArkG1Config as CurveConfig>::ScalarField;
const COFACTOR: &'static [u64] = <ArkG1Config as CurveConfig>::COFACTOR;
const COFACTOR_INV: Self::ScalarField = <ArkG1Config as CurveConfig>::COFACTOR_INV;
}
impl sw::SWCurveConfig for ExtConfig {
const COEFF_A: Self::BaseField = <ArkG1Config as sw::SWCurveConfig>::COEFF_A;
const COEFF_B: Self::BaseField = <ArkG1Config as sw::SWCurveConfig>::COEFF_B;
const GENERATOR: sw::Affine<Self> = sw::Affine::new_unchecked(
<ArkG1Config as sw::SWCurveConfig>::GENERATOR.x,
<ArkG1Config as sw::SWCurveConfig>::GENERATOR.y,
);
}
impl CompatibleConfig<ArkG1Config> for ExtConfig {}
#[test]
fn sw_affine_roundtrip() {
let point: sw::Affine<ArkG1Config> = rand_point();
let ext: sw::Affine<ExtConfig> = point.transmute_into();
let back: &sw::Affine<ArkG1Config> = ext.transmute_ref();
assert_eq!(*back, point);
}
#[test]
fn sw_projective_roundtrip() {
let point: sw::Projective<ArkG1Config> = rand_point();
let ext: sw::Projective<ExtConfig> = point.transmute_into();
let back: &sw::Projective<ArkG1Config> = ext.transmute_ref();
assert_eq!(*back, point);
}
#[test]
fn sw_affine_slice_roundtrip() {
let ark_points: Vec<sw::Affine<ArkG1Config>> = rand_points(5);
let ext_points: Vec<sw::Affine<ExtConfig>> = ark_points
.iter()
.copied()
.map(|p| p.transmute_into())
.collect();
let back: &[sw::Affine<ArkG1Config>] = ext_points.as_slice().transmute_ref();
assert_eq!(back, ark_points.as_slice());
}
}
mod te_test {
use super::*;
use ark_ed25519::EdwardsConfig as ArkTeConfig;
#[derive(Clone, Copy)]
struct ExtConfig;
impl CurveConfig for ExtConfig {
type BaseField = <ArkTeConfig as CurveConfig>::BaseField;
type ScalarField = <ArkTeConfig as CurveConfig>::ScalarField;
const COFACTOR: &'static [u64] = <ArkTeConfig as CurveConfig>::COFACTOR;
const COFACTOR_INV: Self::ScalarField = <ArkTeConfig as CurveConfig>::COFACTOR_INV;
}
impl te::TECurveConfig for ExtConfig {
const COEFF_A: Self::BaseField = <ArkTeConfig as te::TECurveConfig>::COEFF_A;
const COEFF_D: Self::BaseField = <ArkTeConfig as te::TECurveConfig>::COEFF_D;
const GENERATOR: te::Affine<Self> = te::Affine::new_unchecked(
<ArkTeConfig as te::TECurveConfig>::GENERATOR.x,
<ArkTeConfig as te::TECurveConfig>::GENERATOR.y,
);
type MontCurveConfig = ArkTeConfig;
}
impl CompatibleConfig<ArkTeConfig> for ExtConfig {}
#[test]
fn te_affine_roundtrip() {
let point: te::Affine<ArkTeConfig> = rand_point();
let ext: te::Affine<ExtConfig> = point.transmute_into();
let back: &te::Affine<ArkTeConfig> = ext.transmute_ref();
assert_eq!(*back, point);
}
#[test]
fn te_projective_roundtrip() {
let point: te::Projective<ArkTeConfig> = rand_point();
let ext: te::Projective<ExtConfig> = point.transmute_into();
let back: &te::Projective<ArkTeConfig> = ext.transmute_ref();
assert_eq!(*back, point);
}
#[test]
fn te_affine_slice_roundtrip() {
let ark_points: Vec<te::Affine<ArkTeConfig>> = rand_points(5);
let ext_points: Vec<te::Affine<ExtConfig>> = ark_points
.iter()
.copied()
.map(|p| p.transmute_into())
.collect();
let back: &[te::Affine<ArkTeConfig>] = ext_points.as_slice().transmute_ref();
assert_eq!(back, ark_points.as_slice());
}
}
}