halo2curves/pasta/
curve.rs

1use std::convert::TryInto;
2
3use ff::{PrimeField, WithSmallOrderMulGroup};
4
5use super::{fp::Fp, fq::Fq, Pallas, Vesta};
6use crate::{
7    arithmetic::{mul_512, sbb, CurveEndo, EndoParameters},
8    endo,
9};
10
11// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go
12// with `pasta_curves::Fp::ZETA`
13// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md
14// to have more details about the endomorphism.
15const ENDO_PARAMS_EQ: EndoParameters = EndoParameters {
16    // round(b2/n)
17    gamma1: [0x32c49e4c00000003, 0x279a745902a2654e, 0x1, 0x0],
18    // round(-b1/n)
19    gamma2: [0x31f0256800000002, 0x4f34e8b2066389a4, 0x2, 0x0],
20    b1: [0x8cb1279300000001, 0x49e69d1640a89953, 0x0, 0x0],
21    b2: [0x0c7c095a00000001, 0x93cd3a2c8198e269, 0x0, 0x0],
22};
23
24// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go
25// with `pasta_curves::Fq::ZETA`
26// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md
27// to have more details about the endomorphism.
28const ENDO_PARAMS_EP: EndoParameters = EndoParameters {
29    // round(b2/n)
30    gamma1: [0x32c49e4bffffffff, 0x279a745902a2654e, 0x1, 0x0],
31    // round(-b1/n)
32    gamma2: [0x31f0256800000002, 0x4f34e8b2066389a4, 0x2, 0x0],
33    b1: [0x8cb1279300000000, 0x49e69d1640a89953, 0x0, 0x0],
34    b2: [0x0c7c095a00000001, 0x93cd3a2c8198e269, 0x0, 0x0],
35};
36
37endo!(Vesta, Fp, ENDO_PARAMS_EQ);
38endo!(Pallas, Fq, ENDO_PARAMS_EP);
39
40#[cfg(test)]
41mod test {
42    use rand_core::OsRng;
43
44    use super::*;
45
46    #[test]
47    fn test_endo() {
48        use ff::Field;
49
50        for _ in 0..100000 {
51            let k = Fp::random(OsRng);
52            let (k1, k1_neg, k2, k2_neg) = Vesta::decompose_scalar(&k);
53            if k1_neg & k2_neg {
54                assert_eq!(k, -Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2))
55            } else if k1_neg {
56                assert_eq!(k, -Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2))
57            } else if k2_neg {
58                assert_eq!(k, Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2))
59            } else {
60                assert_eq!(k, Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2))
61            }
62        }
63
64        for _ in 0..100000 {
65            let k = Fp::random(OsRng);
66            let (k1, k1_neg, k2, k2_neg) = Vesta::decompose_scalar(&k);
67            if k1_neg & k2_neg {
68                assert_eq!(k, -Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2))
69            } else if k1_neg {
70                assert_eq!(k, -Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2))
71            } else if k2_neg {
72                assert_eq!(k, Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2))
73            } else {
74                assert_eq!(k, Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2))
75            }
76        }
77    }
78}