Skip to main content

ark_vrf/utils/
te_sw_map.rs

1//! # Twisted Edwards to Short Weierstrass curve mapping utilities.
2//!
3//! This module provides bidirectional mappings between different curve representations,
4//! allowing operations to be performed in the most convenient form for a given task.
5
6use ark_ec::{
7    CurveConfig,
8    short_weierstrass::{Affine as SWAffine, SWCurveConfig},
9    twisted_edwards::{Affine as TEAffine, MontCurveConfig, TECurveConfig},
10};
11use ark_ff::{Field, One};
12use ark_std::borrow::Cow;
13
14/// Constants used in mapping TE form to SW form and vice versa.
15/// Configuration trait for curves that support mapping between representations.
16///
17/// This trait must be implemented for curves that need to be converted between
18/// Twisted Edwards, Short Weierstrass, and Montgomery forms.
19pub trait MapConfig: TECurveConfig + SWCurveConfig + MontCurveConfig {
20    /// Precomputed value of Montgomery curve parameter A divided by 3.
21    const MONT_A_OVER_THREE: <Self as CurveConfig>::BaseField;
22
23    /// Precomputed inverse of Montgomery curve parameter B.
24    const MONT_B_INV: <Self as CurveConfig>::BaseField;
25}
26
27/// Map a point in Short Weierstrass form into its corresponding point in Twisted Edwards form.
28///
29/// This function performs the conversion by first mapping from Short Weierstrass to Montgomery form,
30/// then from Montgomery to Twisted Edwards form.
31pub fn sw_to_te<C: MapConfig>(point: &SWAffine<C>) -> Option<TEAffine<C>> {
32    // First map the point from SW to Montgomery
33    // (Bx - A/3, By)
34    let mx = <C as MontCurveConfig>::COEFF_B * point.x - C::MONT_A_OVER_THREE;
35    let my = <C as MontCurveConfig>::COEFF_B * point.y;
36
37    // Then we map the Montgomery point to TE
38    // (x,y) -> (x/y,(x−1)/(x+1))
39    let v_denom = my.inverse()?;
40    let x_p_1 = mx + <<C as CurveConfig>::BaseField as One>::one();
41    let w_denom = x_p_1.inverse()?;
42    let v = mx * v_denom;
43    let w = (mx - <<C as CurveConfig>::BaseField as One>::one()) * w_denom;
44
45    Some(TEAffine::new_unchecked(v, w))
46}
47
48/// Map a point in Twisted Edwards form into its corresponding point in Short Weierstrass form.
49///
50/// This function performs the conversion by first mapping from Twisted Edwards to Montgomery form,
51/// then from Montgomery to Short Weierstrass form.
52pub fn te_to_sw<C: MapConfig>(point: &TEAffine<C>) -> Option<SWAffine<C>> {
53    // Map from TE to Montgomery: (1+y)/(1-y), (1+y)/(x(1-y))
54    let v_denom = <<C as CurveConfig>::BaseField as One>::one() - point.y;
55    let w_denom = point.x - point.x * point.y;
56    let v_denom_inv = v_denom.inverse()?;
57    let w_denom_inv = w_denom.inverse()?;
58    let v_w_num = <<C as CurveConfig>::BaseField as One>::one() + point.y;
59    let v = v_w_num * v_denom_inv;
60    let w = v_w_num * w_denom_inv;
61
62    // Map Montgomery to SW: ((x+A/3)/B,y/B)
63    let x = C::MONT_B_INV * (v + C::MONT_A_OVER_THREE);
64    let y = C::MONT_B_INV * w;
65
66    Some(SWAffine::new_unchecked(x, y))
67}
68
69/// Trait for types that can be converted from/to Short Weierstrass form.
70///
71/// This trait provides methods to convert between a type and its Short Weierstrass representation,
72/// both for individual points and slices of points.
73pub trait SWMapping<C: SWCurveConfig> {
74    /// Convert a Short Weierstrass point to this type.
75    fn from_sw(sw: SWAffine<C>) -> Self;
76
77    /// Convert this type to a Short Weierstrass point.
78    fn into_sw(self) -> SWAffine<C>;
79
80    /// Convert a slice of this type to a slice of Short Weierstrass points.
81    ///
82    /// Returns a borrowed slice if no conversion is needed, or an owned
83    /// vector if conversion is required.
84    fn to_sw_slice(slice: &[Self]) -> Cow<'_, [SWAffine<C>]>
85    where
86        Self: Sized;
87}
88
89impl<C: SWCurveConfig> SWMapping<C> for SWAffine<C> {
90    #[inline(always)]
91    fn from_sw(sw: SWAffine<C>) -> Self {
92        sw
93    }
94
95    #[inline(always)]
96    fn into_sw(self) -> SWAffine<C> {
97        self
98    }
99
100    #[inline(always)]
101    fn to_sw_slice(slice: &[Self]) -> Cow<'_, [SWAffine<C>]> {
102        Cow::Borrowed(slice)
103    }
104}
105
106impl<C: MapConfig> SWMapping<C> for TEAffine<C> {
107    #[inline(always)]
108    fn from_sw(sw: SWAffine<C>) -> Self {
109        sw_to_te(&sw).expect("SW to TE mapping failed (identity or degenerate point)")
110    }
111
112    #[inline(always)]
113    fn into_sw(self) -> SWAffine<C> {
114        te_to_sw(&self).expect("TE to SW mapping failed (identity or degenerate point)")
115    }
116
117    #[inline(always)]
118    fn to_sw_slice(slice: &[Self]) -> Cow<'_, [SWAffine<C>]> {
119        let pks;
120        #[cfg(feature = "parallel")]
121        {
122            use rayon::prelude::*;
123            pks = slice.par_iter().map(|p| p.into_sw()).collect();
124        }
125        #[cfg(not(feature = "parallel"))]
126        {
127            pks = slice.iter().map(|p| p.into_sw()).collect();
128        }
129        Cow::Owned(pks)
130    }
131}
132
133/// Trait for types that can be converted from/to Twisted Edwards form.
134///
135/// This trait provides methods to convert between a type and its Twisted Edwards representation,
136/// both for individual points and slices of points.
137pub trait TEMapping<C: TECurveConfig> {
138    /// Convert a Twisted Edwards point to this type.
139    fn from_te(te: TEAffine<C>) -> Self;
140
141    /// Convert this type to a Twisted Edwards point.
142    fn into_te(self) -> TEAffine<C>;
143
144    /// Convert a slice of this type to a slice of Twisted Edwards points.
145    ///
146    /// Returns a borrowed slice if no conversion is needed, or an owned
147    /// vector if conversion is required.
148    fn to_te_slice(slice: &[Self]) -> Cow<'_, [TEAffine<C>]>
149    where
150        Self: Sized;
151}
152
153impl<C: TECurveConfig> TEMapping<C> for TEAffine<C> {
154    #[inline(always)]
155    fn from_te(te: TEAffine<C>) -> Self {
156        te
157    }
158
159    #[inline(always)]
160    fn into_te(self) -> TEAffine<C> {
161        self
162    }
163
164    #[inline(always)]
165    fn to_te_slice(slice: &[Self]) -> Cow<'_, [TEAffine<C>]> {
166        Cow::Borrowed(slice)
167    }
168}
169
170impl<C: MapConfig> TEMapping<C> for SWAffine<C> {
171    #[inline(always)]
172    fn from_te(te: TEAffine<C>) -> Self {
173        te_to_sw(&te).expect("TE to SW mapping failed (identity or degenerate point)")
174    }
175
176    #[inline(always)]
177    fn into_te(self) -> TEAffine<C> {
178        sw_to_te(&self).expect("SW to TE mapping failed (identity or degenerate point)")
179    }
180
181    #[inline(always)]
182    fn to_te_slice(slice: &[Self]) -> Cow<'_, [TEAffine<C>]> {
183        let pks;
184        #[cfg(feature = "parallel")]
185        {
186            use rayon::prelude::*;
187            pks = slice.par_iter().map(|p| p.into_te()).collect();
188        }
189        #[cfg(not(feature = "parallel"))]
190        {
191            pks = slice.iter().map(|p| p.into_te()).collect();
192        }
193        Cow::Owned(pks)
194    }
195}