openzeppelin_crypto/curve/sw/instance/
secp256k1.rs

1//! This module contains the [secp256k1] curve configuration.
2//!
3//! [secp256k1]: <https://www.secg.org/sec2-v2.pdf>
4use crate::{
5    arithmetic::uint::U256,
6    curve::{
7        sw::{Affine, SWCurveConfig},
8        CurveConfig,
9    },
10    field::fp::{Fp256, FpParams, LIMBS_256},
11    fp_from_num, from_num,
12};
13
14const G_GENERATOR_X: Fq =
15        fp_from_num!("55066263022277343669578718895168534326250603453777594175500187360389116729240");
16
17const G_GENERATOR_Y: Fq =
18        fp_from_num!("32670510020758816978083085130507043184471273380659243275938904335757337482424");
19
20/// Base Field for [`Secp256k1Config`].
21pub type Fq = Fp256<Secp256k1FqParam>;
22/// Base Field parameters for [`Secp256k1Config`].
23pub struct Secp256k1FqParam;
24
25impl FpParams<LIMBS_256> for Secp256k1FqParam {
26    const GENERATOR: Fp256<Self> = fp_from_num!("3");
27    const MODULUS: U256 = from_num!("115792089237316195423570985008687907853269984665640564039457584007908834671663");
28}
29
30/// Scalar Field for [`Secp256k1Config`].
31pub type Fr = Fp256<Secp256k1FrParam>;
32/// Scalar Field parameters for [`Secp256k1Config`].
33pub struct Secp256k1FrParam;
34
35impl FpParams<LIMBS_256> for Secp256k1FrParam {
36    const GENERATOR: Fp256<Self> = fp_from_num!("7");
37    const MODULUS: U256 = from_num!("115792089237316195423570985008687907852837564279074904382605163141518161494337");
38}
39
40/// secp256k1's Curve Details.
41#[derive(Clone, Default, PartialEq, Eq)]
42pub struct Secp256k1Config;
43
44impl CurveConfig for Secp256k1Config {
45    type BaseField = Fq;
46    type ScalarField = Fr;
47
48    const COFACTOR: &'static [u64] = &[0x1, 0x0];
49    const COFACTOR_INV: Fr = Fr::ONE;
50}
51
52impl SWCurveConfig for Secp256k1Config {
53    const COEFF_A: Fq = Fq::ZERO;
54    const COEFF_B: Fq = fp_from_num!("7");
55    const GENERATOR: Affine<Self> =
56        Affine::new_unchecked(G_GENERATOR_X, G_GENERATOR_Y);
57}
58
59#[cfg(test)]
60mod test {
61    use alloc::vec::Vec;
62
63    use num_traits::Zero;
64    use proptest::{arbitrary::any, prelude::prop, proptest};
65
66    use crate::{
67        curve::{
68            sw::{
69                instance::secp256k1::{Fq, Fr, Secp256k1Config},
70                Affine, Projective,
71            },
72            AffineRepr, CurveConfig, CurveGroup,
73        },
74        field::group::AdditiveGroup,
75        fp_from_hex,
76    };
77
78    // Values generated with "algebra" implementation of secp256k1 curve.
79    // https://github.com/arkworks-rs/algebra/blob/48ec86ef03f700244a5a24d38a751959ab64fd3e/curves/secp256k1/src/curves/mod.rs#L16
80
81    #[test]
82    fn scalar_mul() {
83        assert!(
84            Affine::<Secp256k1Config>::generator()
85                .mul_bigint(0u32)
86                .into_affine()
87                .infinity
88        );
89
90        let result: Vec<_> = (1u32..25)
91            .map(|k| {
92                Affine::<Secp256k1Config>::generator()
93                    .mul_bigint(k)
94                    .into_affine()
95            })
96            .collect();
97
98        let expected =
99            [
100                (fp_from_hex!("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"), fp_from_hex!("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")),
101                (fp_from_hex!("C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5"), fp_from_hex!("1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A")),
102                (fp_from_hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), fp_from_hex!("388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672")),
103                (fp_from_hex!("E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13"), fp_from_hex!("51ED993EA0D455B75642E2098EA51448D967AE33BFBDFE40CFE97BDC47739922")),
104                (fp_from_hex!("2F8BDE4D1A07209355B4A7250A5C5128E88B84BDDC619AB7CBA8D569B240EFE4"), fp_from_hex!("D8AC222636E5E3D6D4DBA9DDA6C9C426F788271BAB0D6840DCA87D3AA6AC62D6")),
105                (fp_from_hex!("FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556"), fp_from_hex!("AE12777AACFBB620F3BE96017F45C560DE80F0F6518FE4A03C870C36B075F297")),
106                (fp_from_hex!("5CBDF0646E5DB4EAA398F365F2EA7A0E3D419B7E0330E39CE92BDDEDCAC4F9BC"), fp_from_hex!("6AEBCA40BA255960A3178D6D861A54DBA813D0B813FDE7B5A5082628087264DA")),
107                (fp_from_hex!("2F01E5E15CCA351DAFF3843FB70F3C2F0A1BDD05E5AF888A67784EF3E10A2A01"), fp_from_hex!("5C4DA8A741539949293D082A132D13B4C2E213D6BA5B7617B5DA2CB76CBDE904")),
108                (fp_from_hex!("ACD484E2F0C7F65309AD178A9F559ABDE09796974C57E714C35F110DFC27CCBE"), fp_from_hex!("CC338921B0A7D9FD64380971763B61E9ADD888A4375F8E0F05CC262AC64F9C37")),
109                (fp_from_hex!("A0434D9E47F3C86235477C7B1AE6AE5D3442D49B1943C2B752A68E2A47E247C7"), fp_from_hex!("893ABA425419BC27A3B6C7E693A24C696F794C2ED877A1593CBEE53B037368D7")),
110                (fp_from_hex!("774AE7F858A9411E5EF4246B70C65AAC5649980BE5C17891BBEC17895DA008CB"), fp_from_hex!("D984A032EB6B5E190243DD56D7B7B365372DB1E2DFF9D6A8301D74C9C953C61B")),
111                (fp_from_hex!("D01115D548E7561B15C38F004D734633687CF4419620095BC5B0F47070AFE85A"), fp_from_hex!("A9F34FFDC815E0D7A8B64537E17BD81579238C5DD9A86D526B051B13F4062327")),
112                (fp_from_hex!("F28773C2D975288BC7D1D205C3748651B075FBC6610E58CDDEEDDF8F19405AA8"), fp_from_hex!("AB0902E8D880A89758212EB65CDAF473A1A06DA521FA91F29B5CB52DB03ED81")),
113                (fp_from_hex!("499FDF9E895E719CFD64E67F07D38E3226AA7B63678949E6E49B241A60E823E4"), fp_from_hex!("CAC2F6C4B54E855190F044E4A7B3D464464279C27A3F95BCC65F40D403A13F5B")),
114                (fp_from_hex!("D7924D4F7D43EA965A465AE3095FF41131E5946F3C85F79E44ADBCF8E27E080E"), fp_from_hex!("581E2872A86C72A683842EC228CC6DEFEA40AF2BD896D3A5C504DC9FF6A26B58")),
115                (fp_from_hex!("E60FCE93B59E9EC53011AABC21C23E97B2A31369B87A5AE9C44EE89E2A6DEC0A"), fp_from_hex!("F7E3507399E595929DB99F34F57937101296891E44D23F0BE1F32CCE69616821")),
116                (fp_from_hex!("DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"), fp_from_hex!("4211AB0694635168E997B0EAD2A93DAECED1F4A04A95C0F6CFB199F69E56EB77")),
117                (fp_from_hex!("5601570CB47F238D2B0286DB4A990FA0F3BA28D1A319F5E7CF55C2A2444DA7CC"), fp_from_hex!("C136C1DC0CBEB930E9E298043589351D81D8E0BC736AE2A1F5192E5E8B061D58")),
118                (fp_from_hex!("2B4EA0A797A443D293EF5CFF444F4979F06ACFEBD7E86D277475656138385B6C"), fp_from_hex!("85E89BC037945D93B343083B5A1C86131A01F60C50269763B570C854E5C09B7A")),
119                (fp_from_hex!("4CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97"), fp_from_hex!("12BA26DCB10EC1625DA61FA10A844C676162948271D96967450288EE9233DC3A")),
120                (fp_from_hex!("352BBF4A4CDD12564F93FA332CE333301D9AD40271F8107181340AEF25BE59D5"), fp_from_hex!("321EB4075348F534D59C18259DDA3E1F4A1B3B2E71B1039C67BD3D8BCF81998C")),
121                (fp_from_hex!("421F5FC9A21065445C96FDB91C0C1E2F2431741C72713B4B99DDCB316F31E9FC"), fp_from_hex!("2B90F16D11DABDB616F6DB7E225D1E14743034B37B223115DB20717AD1CD6781")),
122                (fp_from_hex!("2FA2104D6B38D11B0230010559879124E42AB8DFEFF5FF29DC9CDADD4ECACC3F"), fp_from_hex!("2DE1068295DD865B64569335BD5DD80181D70ECFC882648423BA76B532B7D67")),
123                (fp_from_hex!("FE72C435413D33D48AC09C9161BA8B09683215439D62B7940502BDA8B202E6CE"), fp_from_hex!("6851DE067FF24A68D3AB47E09D72998101DC88E36B4A9D22978ED2FBCF58C5BF")),
124            ];
125
126        for (result, (expected_x, expected_y)) in result.iter().zip(expected) {
127            assert!(result.is_on_curve());
128            assert_eq!(result.x, expected_x);
129            assert_eq!(result.y, expected_y);
130        }
131    }
132
133    #[test]
134    fn point_add() {
135        let g = Affine::<Secp256k1Config>::generator();
136        let g_proj: Projective<Secp256k1Config> = g.into();
137
138        // Test G + G = 2G
139        let expected_g2 = Affine::new_unchecked(
140            fp_from_hex!("C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5"),
141            fp_from_hex!("1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A"),
142        );
143        let g2 = g_proj + g;
144        let g2_affine = g2.into_affine();
145        assert_eq!(g2_affine, expected_g2);
146        let g2_affine = g_proj.double().into_affine();
147        assert_eq!(g2_affine, expected_g2);
148
149        // Test G + (-G) = 0
150        let neg_g = -g_proj;
151        let zero = g_proj + neg_g;
152        assert!(zero.is_zero());
153    }
154
155    #[test]
156    fn point_sub() {
157        let g = Affine::<Secp256k1Config>::generator();
158        let g_proj: Projective<Secp256k1Config> = g.into();
159
160        // Test G - G = 0
161        let zero = g_proj - g_proj;
162        assert!(zero.is_zero());
163
164        // Test 2G - G = G
165        let g2: Projective<Secp256k1Config> = Affine::new_unchecked(
166            fp_from_hex!("C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5"),
167            fp_from_hex!("1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A"),
168        ).into();
169        assert_eq!(g2 - g_proj, g_proj);
170    }
171
172    #[test]
173    fn cofactor_is_one() {
174        #[derive(Clone, Default, PartialEq, Eq)]
175        struct NotOneCofactorConfig;
176
177        impl CurveConfig for NotOneCofactorConfig {
178            type BaseField = Fq;
179            type ScalarField = Fr;
180
181            const COFACTOR: &'static [u64] = &[0x0, 0x0, 0x0, 0x1, 0x0];
182            const COFACTOR_INV: Fr = Fr::ONE;
183        }
184
185        assert!(Secp256k1Config::cofactor_is_one());
186        assert!(!NotOneCofactorConfig::cofactor_is_one());
187    }
188
189    #[test]
190    fn normalize_batch() {
191        // Larger collection makes test pass noticeably longer.
192        proptest!(|(scalars in prop::collection::vec(any::<u32>(), 1..10))|{
193            let prj_points: Vec<_> = scalars.iter()
194                .map(|&k| Affine::<Secp256k1Config>::generator().mul_bigint(k))
195                .collect();
196
197            let expected_aff_points: Vec<_> =
198                prj_points.iter().map(|prj| prj.into_affine()).collect();
199
200            let aff_points =
201                Projective::<Secp256k1Config>::normalize_batch(&prj_points);
202
203            assert_eq!(aff_points, expected_aff_points);
204        });
205    }
206}