openzeppelin_crypto/curve/te/instance/
jubjub.rs

1//! This module contains the [Jubjub Elliptic Curve] configuration.
2//!
3//! [Jubjub Elliptic Curve]: <https://zips.z.cash/protocol/protocol.pdf>
4
5use crate::{
6    arithmetic::uint::U256,
7    curve::{
8        te::{Affine, MontCurveConfig, TECurveConfig},
9        CurveConfig,
10    },
11    field::fp::{Fp256, FpParams, LIMBS_256},
12    fp_from_num, from_num,
13};
14
15const G_GENERATOR_X: Fq = fp_from_num!("8076246640662884909881801758704306714034609987455869804520522091855516602923");
16const G_GENERATOR_Y: Fq = fp_from_num!("13262374693698910701929044844600465831413122818447359594527400194675274060458");
17
18/// Base Field for [`JubjubConfig`].
19pub type Fq = Fp256<JubjubFqParam>;
20/// Base Field parameters for [`JubjubConfig`].
21pub struct JubjubFqParam;
22
23impl FpParams<LIMBS_256> for JubjubFqParam {
24    const GENERATOR: Fp256<Self> = fp_from_num!("5");
25    const MODULUS: U256 = from_num!("52435875175126190479447740508185965837690552500527637822603658699938581184513");
26}
27
28/// Scalar Field for [`JubjubConfig`].
29pub type Fr = Fp256<JubjubFrParam>;
30/// Scalar Field parameters for [`JubjubConfig`].
31pub struct JubjubFrParam;
32
33impl FpParams<LIMBS_256> for JubjubFrParam {
34    const GENERATOR: Fp256<Self> = fp_from_num!("5");
35    const MODULUS: U256 = from_num!("6554484396890773809930967563523245729705921265872317281365359162392183254199");
36}
37
38/// Jubjub Curve Details.
39#[derive(Clone, Default, PartialEq, Eq)]
40pub struct JubjubConfig;
41
42impl CurveConfig for JubjubConfig {
43    type BaseField = Fq;
44    type ScalarField = Fr;
45
46    const COFACTOR: &'static [u64] = &[8];
47    const COFACTOR_INV: Fr = fp_from_num!("819310549611346726241370945440405716213240158234039660170669895299022906775");
48}
49
50impl TECurveConfig for JubjubConfig {
51    type MontCurveConfig = Self;
52
53    const COEFF_A: Self::BaseField = fp_from_num!("1").neg();
54    const COEFF_D: Self::BaseField = fp_from_num!("19257038036680949359750312669786877991949435402254120286184196891950884077233");
55    const GENERATOR: Affine<Self> =
56        Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y);
57}
58
59impl MontCurveConfig for JubjubConfig {
60    type TECurveConfig = Self;
61
62    const COEFF_A: Self::BaseField = fp_from_num!("40962");
63    const COEFF_B: Self::BaseField = fp_from_num!("1");
64}
65
66#[cfg(test)]
67mod test {
68    use num_traits::Zero;
69
70    use crate::{
71        curve::{
72            te::{instance::jubjub::JubjubConfig, Affine, Projective},
73            AffineRepr, CurveGroup,
74        },
75        field::group::AdditiveGroup,
76        fp_from_hex,
77    };
78
79    // Values generated with "algebra" implementation of JubJub curve.
80    // https://github.com/arkworks-rs/algebra/blob/48ec86ef03f700244a5a24d38a751959ab64fd3e/curves/ed_on_bls12_381/src/curves/mod.rs#L52
81
82    #[test]
83    fn scalar_mul() {
84        assert!(Affine::<JubjubConfig>::generator()
85            .mul_bigint(0u32)
86            .into_affine()
87            .is_zero());
88
89        let result: Vec<_> = (1u32..25)
90            .map(|k| {
91                Affine::<JubjubConfig>::generator().mul_bigint(k).into_affine()
92            })
93            .collect();
94
95        let expected = [
96            (fp_from_hex!("11DAFE5D23E1218086A365B99FBF3D3BE72F6AFD7D1F72623E6B071492D1122B"), fp_from_hex!("1D523CF1DDAB1A1793132E78C866C0C33E26BA5CC220FED7CC3F870E59D292AA")),
97            (fp_from_hex!("422AA5019E2B74D23B9F975158AB150BC4CC70D281A909DF8A8A9A5DEBE99DCD"), fp_from_hex!("10605562D77B78BC4B7CA1EA62681C850B71E55C81BE7BDB8C9285CC60C9D31")),
98            (fp_from_hex!("652D7E33D516D7B1227104A74EF543849906DFB3DE4F5131396F8B6B7811CC53"), fp_from_hex!("3F42D97086BBF60795D64EE198CDE129B76256CC29F3881177ECC5045084519D")),
99            (fp_from_hex!("4700C53930F4ECFA0D58A6D76F3BF22C7FAEB657E16EF540BC6C3368C7E2531F"), fp_from_hex!("3FB7BF5EB8791A69B20113A1D33668DD4E629381ED8B99011A2E36E866D07C8")),
100            (fp_from_hex!("58BB4D87A7F00B0AF420F3F879C5E8F9D2187A0E5CAF4A9CDA29C3B6A63F70AE"), fp_from_hex!("52E89296DC23C170390EE73C5F00EF2F532943FE9F7869CEBF2CD7BA4585569E")),
101            (fp_from_hex!("4975D528AD4BE06E6313AE454257A0AD97C6B17E038D2864C36B25B4304C7531"), fp_from_hex!("55DD3A252F249B2DDC8B0C4346E537B54C73CE111980ABE7B356856A9EA96D2B")),
102            (fp_from_hex!("6A9C4646E21B0090F82894E77A4C05EA9DA9580B66996C272CC133E42099381F"), fp_from_hex!("3C493C78419C7CC5D07721405A8F736DE62E21A0D9C877A44C7E8F7A53D069F0")),
103            (fp_from_hex!("73C4CD5B80651A4469BBD50BAB74CB2C4756284A06EB7B059A16CA306EDA7648"), fp_from_hex!("1A95E7A9D0B0E85316BEE41F6642267BBF09BC00FDAF722F733550A41524BA69")),
104            (fp_from_hex!("15DA087293CA2FB980EF297142B2B644C3E1B501FA50ECF4C822543CEAB42C5A"), fp_from_hex!("3CC7A7997E7BF44164C4B34C7D4A2537694974E6167B99DB6DA192E8FA6A6FC4")),
105            (fp_from_hex!("58A5E87F3845956D9EA68D5D2FBC41C50C0C56549D86879209CA5D7131E149AA"), fp_from_hex!("4E2D421EE96ADAF44F03E4F344D60E48FE5E42B9D762BF8870D43AA8982D6E87")),
106            (fp_from_hex!("12C49B6A863295C8697D153BEA9BA9923D2F812C5211CAE487A72AE19A000B41"), fp_from_hex!("2456B44CE4D259A923CA6786F5CC79154F13317BB2B59A2E9156037DACA9F604")),
107            (fp_from_hex!("1B6C98BDDAAEF5834FD3312D3EDC987B7589111F7618BB940C9EA82D311807BA"), fp_from_hex!("105C7F09867BA9BCAC7F9E07E53DFBE08A409039C00DBCFB69E3710D70AFC0BE")),
108            (fp_from_hex!("260DA92F0ABB09310425D7D2A8CF5315F75FF454A470D730B4C6188A602536B2"), fp_from_hex!("3B787A68C84E40522127B4C7645A9CC696920923E7828698B233FB5C3716BE26")),
109            (fp_from_hex!("5FBAF04757E89603623F37C63BFBF8952BCCE339375FBD7BB8EA56E1F38F0FAC"), fp_from_hex!("604394C440FF857DF9CE55CFBDC21CDEB80EDC54372EE437E4CB70730BC27424")),
110            (fp_from_hex!("43BCB99D818C1C6EDC1C188FD7C19DA1A25530B9577AD1D9FBE0692FE73E790D"), fp_from_hex!("33943278860345A2AB5E4F6E905D920A60F820BE00A8947D69BF11ECB5E19153")),
111            (fp_from_hex!("893B41DB313DF97FD953FB743E8350C54C8D833BDE838BC28A84323D0835F07"), fp_from_hex!("67EFD78A2EF6E7EA6B3DEABE4689411B9383EAF47ABC317152D46820CAB0B2A8")),
112            (fp_from_hex!("732671449FA098C16425BD0E3D613892AA4E2459DEDBA426FC4D5D1E712F38D5"), fp_from_hex!("27B59986C0320F4CC8CD7A1D656E5DCC83E201E7E3E5339E288761A6A5E2345B")),
113            (fp_from_hex!("2AD7BEDBC9ED7D8DB3971A37719874B171B18C8EF9E11BE9E70630499185AD50"), fp_from_hex!("28454969555C5EE194012C8C98A2A35EA726B4C5D08E95C6A3FAD5061EEF18E")),
114            (fp_from_hex!("2C8A1DEE04AF91AF42CF91EBC311B1F7C4F52A4F66F1D13508844846539D72A9"), fp_from_hex!("4867FDCBDED9DBCDB460A342479F787FC7A0B1B7E5AFB1CA361D0AA69E2208BF")),
115            (fp_from_hex!("3B30A57702DB2F24AB18568F1B58F5D748C8EFF5F65A6A6419081C4EC8EC2785"), fp_from_hex!("23BF96E00F5B4C4E97C1C0D2DE1456D9F993A3DB92E249626323D5E2D64C0652")),
116            (fp_from_hex!("15D40819865683827265B49A103973995910D10531FCA0D31BEFD89F09F10A43"), fp_from_hex!("6C66F5359CFE230B654863A69DD46380BABDB87F7CF5D5C4EA818737F670C376")),
117            (fp_from_hex!("A286B2156E0C34B65F3C92EBE94B11604D57E54275219F95CAD1D55A3F2CF2A"), fp_from_hex!("3CE1555E95000126EC9078B3A9DE17F897654EE803BE674457DFD170EA7ADE23")),
118            (fp_from_hex!("2D15FC55F5D964000CA21698D1581F136C9401696CA49D6CB186849A528961D1"), fp_from_hex!("F06D0B4495BE176A33E1CAEA9455B0F810F43333D1B740E39A19200213AC020")),
119            (fp_from_hex!("3EE1AECF577DBBC33809E69C629418BFA4384D5CB38B331739B1D1747308F095"), fp_from_hex!("40410A13A94EACAE90F61DFF11793025144DCC07E6CCC6BA3B0728605BF70D56")),
120        ];
121
122        for (result, (expected_x, expected_y)) in result.iter().zip(expected) {
123            assert!(result.is_on_curve());
124            assert_eq!(result.x, expected_x);
125            assert_eq!(result.y, expected_y);
126        }
127    }
128
129    #[test]
130    fn point_add() {
131        let g = Affine::<JubjubConfig>::generator();
132        let g_proj: Projective<JubjubConfig> = g.into();
133
134        // Test G + G = 2G
135        let expected_g2 = Affine::new_unchecked(
136            fp_from_hex!("422AA5019E2B74D23B9F975158AB150BC4CC70D281A909DF8A8A9A5DEBE99DCD"),
137            fp_from_hex!("10605562D77B78BC4B7CA1EA62681C850B71E55C81BE7BDB8C9285CC60C9D31"),
138        );
139        let g2 = g_proj + g;
140        let g2_affine = g2.into_affine();
141        assert_eq!(g2_affine, expected_g2);
142        let g2_affine = g_proj.double().into_affine();
143        assert_eq!(g2_affine, expected_g2);
144
145        // Test G + (-G) = 0
146        let neg_g = -g_proj;
147        let zero = g_proj + neg_g;
148        assert!(zero.is_zero());
149    }
150
151    #[test]
152    fn point_sub() {
153        let g = Affine::<JubjubConfig>::generator();
154        let g_proj: Projective<JubjubConfig> = g.into();
155
156        // Test G - G = 0
157        let zero = g_proj - g_proj;
158        assert!(zero.is_zero());
159
160        // Test 2G - G = G
161        let g2: Projective<JubjubConfig> = Affine::new_unchecked(
162            fp_from_hex!("422AA5019E2B74D23B9F975158AB150BC4CC70D281A909DF8A8A9A5DEBE99DCD"),
163            fp_from_hex!("10605562D77B78BC4B7CA1EA62681C850B71E55C81BE7BDB8C9285CC60C9D31"),
164        ).into();
165        assert_eq!(g2 - g_proj, g_proj);
166    }
167}