jf_relation/gadgets/ecc/
conversion.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! this file implements the conversion logic for elliptic curve point between
8//! - short Weierstrass form
9//! - twisted Edwards form
10//!
11//! Note that the APIs below create no circuits.
12//! An entity should either know both the SW and TE form of a
13//! point; or know none of the two. There is no need to generate
14//! a circuit for arguing secret knowledge of one form while
15//! the other form is public. In practice a prover will convert all of the
16//! points to the TE form and work on the TE form inside the circuits.
17
18use super::TEPoint;
19use ark_ec::short_weierstrass::{Affine as SWAffine, SWCurveConfig as SWParam};
20use ark_ff::{BigInteger256, BigInteger384, BigInteger768, PrimeField};
21
22impl<F, P> From<SWAffine<P>> for TEPoint<F>
23where
24    F: PrimeField + SWToTEConParam,
25    P: SWParam<BaseField = F>,
26{
27    fn from(p: SWAffine<P>) -> Self {
28        // this function is only correct for BLS12-377
29        // (other curves does not impl an SW form)
30
31        // if p is an infinity point
32        // return infinity point
33        if p.infinity {
34            return Self(F::zero(), F::one());
35        }
36
37        // we need to firstly convert this point into
38        // TE form, and then build the point
39
40        // safe unwrap
41        let s = F::from(F::S);
42        let neg_alpha = F::from(F::NEG_ALPHA);
43        let beta = F::from(F::BETA);
44
45        // we first transform the Weierstrass point (px, py) to Montgomery point (mx,
46        // my) where mx = s * (px - alpha)
47        // my = s * py
48        let montgomery_x = s * (p.x + neg_alpha);
49        let montgomery_y = s * p.y;
50        // then we transform the Montgomery point (mx, my) to TE point (ex, ey) where
51        // ex = beta * mx / my
52        // ey = (mx - 1) / (mx + 1)
53        let edwards_x = beta * montgomery_x / montgomery_y;
54        let edwards_y = (montgomery_x - F::one()) / (montgomery_x + F::one());
55
56        TEPoint(edwards_x, edwards_y)
57    }
58}
59
60/// This trait holds constants that are used for curve conversion from
61/// short Weierstrass form to twisted Edwards form.
62pub trait SWToTEConParam: PrimeField {
63    /// Parameter S.
64    const S: Self::BigInt;
65    /// Parameter 1/alpha.
66    const NEG_ALPHA: Self::BigInt;
67    /// Parameter beta.
68    const BETA: Self::BigInt;
69}
70
71// ================================================
72// BLS12-377::Fq specific implementations
73// ================================================
74use ark_bls12_377::Fq as Fq377;
75impl SWToTEConParam for Fq377 {
76    // s = 10189023633222963290707194929886294091415157242906428298294512798502806398782149227503530278436336312243746741931
77    const S: Self::BigInt = BigInteger384::new([
78        0x3401d618f0339eab,
79        0x0f793b8504b428d4,
80        0x0ff643cca95ccc0d,
81        0xd7a504665d66cc8c,
82        0x1dc07a44b1eeea84,
83        0x10f272020f118a,
84    ]);
85
86    // alpha = -1
87    const NEG_ALPHA: Self::BigInt = BigInteger384::new([1, 0, 0, 0, 0, 0]);
88
89    // beta = 23560188534917577818843641916571445935985386319233886518929971599490231428764380923487987729215299304184915158756
90    const BETA: Self::BigInt = BigInteger384::new([
91        0x450ae9206343e6e4,
92        0x7af39509df5027b6,
93        0xab82b31405cf8a30,
94        0x80d743e1f6c15c7c,
95        0x0cec22e650360183,
96        0x272fd56ac5c669,
97    ]);
98}
99
100// ================================================
101// Bn254::Fq dummy implementations
102// ================================================
103use ark_bn254::Fq as Fq254;
104/// Dummy implementation for trait bounds
105impl SWToTEConParam for Fq254 {
106    const S: Self::BigInt = BigInteger256::new([0, 0, 0, 0]);
107    const NEG_ALPHA: Self::BigInt = BigInteger256::new([0, 0, 0, 0]);
108    const BETA: Self::BigInt = BigInteger256::new([0, 0, 0, 0]);
109}
110
111// ================================================
112// Bls12-381::Fq dummy implementations
113// ================================================
114use ark_bls12_381::Fq as Fq381;
115/// Dummy implementation for trait bounds
116impl SWToTEConParam for Fq381 {
117    const S: Self::BigInt = BigInteger384::new([0, 0, 0, 0, 0, 0]);
118    const NEG_ALPHA: Self::BigInt = BigInteger384::new([0, 0, 0, 0, 0, 0]);
119    const BETA: Self::BigInt = BigInteger384::new([0, 0, 0, 0, 0, 0]);
120}
121
122// ================================================
123// Bw6-761::Fq dummy implementations
124// ================================================
125use ark_bw6_761::Fq as Fq761;
126/// Dummy implementation for trait bounds
127impl SWToTEConParam for Fq761 {
128    const S: Self::BigInt = BigInteger768::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
129    const NEG_ALPHA: Self::BigInt = BigInteger768::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
130    const BETA: Self::BigInt = BigInteger768::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
131}
132
133#[cfg(test)]
134mod test {
135    use super::*;
136    use ark_bls12_377::{G1Affine, G1Projective};
137    use ark_ec::{AffineRepr, CurveGroup};
138    use ark_ff::{MontFp, One};
139    use ark_std::{UniformRand, Zero};
140    use jf_utils::test_rng;
141
142    // a helper function to check if a point is on the ed curve
143    // of bls12-377 G1
144    fn is_on_bls12_377_ed_curve(p: &TEPoint<Fq377>) -> bool {
145        // Twisted Edwards curve 2: a * x² + y² = 1 + d * x² * y²
146        let a = MontFp!("-1");
147        let d = MontFp!("122268283598675559488486339158635529096981886914877139579534153582033676785385790730042363341236035746924960903179");
148
149        let x2 = p.0 * p.0;
150        let y2 = p.1 * p.1;
151
152        let left = a * x2 + y2;
153        let right = Fq377::one() + d * x2 * y2;
154
155        left == right
156    }
157
158    #[allow(non_snake_case)]
159    #[test]
160    fn test_sw_to_te_conversion() {
161        let mut rng = test_rng();
162
163        // test generator
164        let g1 = G1Affine::generator();
165        let p: TEPoint<Fq377> = g1.into();
166        assert!(is_on_bls12_377_ed_curve(&p));
167
168        // test zero point
169        let g1 = G1Affine::zero();
170        let p: TEPoint<Fq377> = g1.into();
171        assert_eq!(p.0, Fq377::zero());
172        assert_eq!(p.1, Fq377::one());
173        assert!(is_on_bls12_377_ed_curve(&p));
174
175        // test a random group element
176        let g1 = G1Projective::rand(&mut rng).into_affine();
177        let p: TEPoint<Fq377> = g1.into();
178        assert!(is_on_bls12_377_ed_curve(&p));
179    }
180}