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