jf_relation/gadgets/ecc/
conversion.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright (c) 2022 Espresso Systems (espressosys.com)
// This file is part of the Jellyfish library.

// You should have received a copy of the MIT License
// along with the Jellyfish library. If not, see <https://mit-license.org/>.

//! this file implements the conversion logic for elliptic curve point between
//! - short Weierstrass form
//! - twisted Edwards form
//!
//! Note that the APIs below create no circuits.
//! An entity should either know both the SW and TE form of a
//! point; or know none of the two. There is no need to generate
//! a circuit for arguing secret knowledge of one form while
//! the other form is public. In practice a prover will convert all of the
//! points to the TE form and work on the TE form inside the circuits.

use super::TEPoint;
use ark_ec::short_weierstrass::{Affine as SWAffine, SWCurveConfig as SWParam};
use ark_ff::{BigInteger256, BigInteger384, BigInteger768, PrimeField};

impl<F, P> From<SWAffine<P>> for TEPoint<F>
where
    F: PrimeField + SWToTEConParam,
    P: SWParam<BaseField = F>,
{
    fn from(p: SWAffine<P>) -> Self {
        // this function is only correct for BLS12-377
        // (other curves does not impl an SW form)

        // if p is an infinity point
        // return infinity point
        if p.infinity {
            return Self(F::zero(), F::one());
        }

        // we need to firstly convert this point into
        // TE form, and then build the point

        // safe unwrap
        let s = F::from(F::S);
        let neg_alpha = F::from(F::NEG_ALPHA);
        let beta = F::from(F::BETA);

        // we first transform the Weierstrass point (px, py) to Montgomery point (mx,
        // my) where mx = s * (px - alpha)
        // my = s * py
        let montgomery_x = s * (p.x + neg_alpha);
        let montgomery_y = s * p.y;
        // then we transform the Montgomery point (mx, my) to TE point (ex, ey) where
        // ex = beta * mx / my
        // ey = (mx - 1) / (mx + 1)
        let edwards_x = beta * montgomery_x / montgomery_y;
        let edwards_y = (montgomery_x - F::one()) / (montgomery_x + F::one());

        TEPoint(edwards_x, edwards_y)
    }
}

/// This trait holds constants that are used for curve conversion from
/// short Weierstrass form to twisted Edwards form.
pub trait SWToTEConParam: PrimeField {
    /// Parameter S.
    const S: Self::BigInt;
    /// Parameter 1/alpha.
    const NEG_ALPHA: Self::BigInt;
    /// Parameter beta.
    const BETA: Self::BigInt;
}

// ================================================
// BLS12-377::Fq specific implementations
// ================================================
use ark_bls12_377::Fq as Fq377;
impl SWToTEConParam for Fq377 {
    // s = 10189023633222963290707194929886294091415157242906428298294512798502806398782149227503530278436336312243746741931
    const S: Self::BigInt = BigInteger384::new([
        0x3401d618f0339eab,
        0x0f793b8504b428d4,
        0x0ff643cca95ccc0d,
        0xd7a504665d66cc8c,
        0x1dc07a44b1eeea84,
        0x10f272020f118a,
    ]);

    // alpha = -1
    const NEG_ALPHA: Self::BigInt = BigInteger384::new([1, 0, 0, 0, 0, 0]);

    // beta = 23560188534917577818843641916571445935985386319233886518929971599490231428764380923487987729215299304184915158756
    const BETA: Self::BigInt = BigInteger384::new([
        0x450ae9206343e6e4,
        0x7af39509df5027b6,
        0xab82b31405cf8a30,
        0x80d743e1f6c15c7c,
        0x0cec22e650360183,
        0x272fd56ac5c669,
    ]);
}

// ================================================
// Bn254::Fq dummy implementations
// ================================================
use ark_bn254::Fq as Fq254;
/// Dummy implementation for trait bounds
impl SWToTEConParam for Fq254 {
    const S: Self::BigInt = BigInteger256::new([0, 0, 0, 0]);
    const NEG_ALPHA: Self::BigInt = BigInteger256::new([0, 0, 0, 0]);
    const BETA: Self::BigInt = BigInteger256::new([0, 0, 0, 0]);
}

// ================================================
// Bls12-381::Fq dummy implementations
// ================================================
use ark_bls12_381::Fq as Fq381;
/// Dummy implementation for trait bounds
impl SWToTEConParam for Fq381 {
    const S: Self::BigInt = BigInteger384::new([0, 0, 0, 0, 0, 0]);
    const NEG_ALPHA: Self::BigInt = BigInteger384::new([0, 0, 0, 0, 0, 0]);
    const BETA: Self::BigInt = BigInteger384::new([0, 0, 0, 0, 0, 0]);
}

// ================================================
// Bw6-761::Fq dummy implementations
// ================================================
use ark_bw6_761::Fq as Fq761;
/// Dummy implementation for trait bounds
impl SWToTEConParam for Fq761 {
    const S: Self::BigInt = BigInteger768::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
    const NEG_ALPHA: Self::BigInt = BigInteger768::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
    const BETA: Self::BigInt = BigInteger768::new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
}

#[cfg(test)]
mod test {
    use super::*;
    use ark_bls12_377::{G1Affine, G1Projective};
    use ark_ec::{AffineRepr, CurveGroup};
    use ark_ff::{MontFp, One};
    use ark_std::{UniformRand, Zero};
    use jf_utils::test_rng;

    // a helper function to check if a point is on the ed curve
    // of bls12-377 G1
    fn is_on_bls12_377_ed_curve(p: &TEPoint<Fq377>) -> bool {
        // Twisted Edwards curve 2: a * x² + y² = 1 + d * x² * y²
        let a = MontFp!("-1");
        let d = MontFp!("122268283598675559488486339158635529096981886914877139579534153582033676785385790730042363341236035746924960903179");

        let x2 = p.0 * p.0;
        let y2 = p.1 * p.1;

        let left = a * x2 + y2;
        let right = Fq377::one() + d * x2 * y2;

        left == right
    }

    #[allow(non_snake_case)]
    #[test]
    fn test_sw_to_te_conversion() {
        let mut rng = test_rng();

        // test generator
        let g1 = G1Affine::generator();
        let p: TEPoint<Fq377> = g1.into();
        assert!(is_on_bls12_377_ed_curve(&p));

        // test zero point
        let g1 = G1Affine::zero();
        let p: TEPoint<Fq377> = g1.into();
        assert_eq!(p.0, Fq377::zero());
        assert_eq!(p.1, Fq377::one());
        assert!(is_on_bls12_377_ed_curve(&p));

        // test a random group element
        let g1 = G1Projective::rand(&mut rng).into_affine();
        let p: TEPoint<Fq377> = g1.into();
        assert!(is_on_bls12_377_ed_curve(&p));
    }
}