cfxkey/
math.rs

1// Copyright 2015-2019 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3
4// Parity Ethereum is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Ethereum is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17use super::{Error, Public, Secret, SECP256K1};
18use cfx_types::{BigEndianHash as _, H256, U256};
19use secp256k1::{
20    constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y},
21    key,
22};
23
24/// Whether the public key is valid.
25pub fn public_is_valid(public: &Public) -> bool {
26    to_secp256k1_public(public)
27        .ok()
28        .map_or(false, |p| p.is_valid())
29}
30
31/// Inplace multiply public key by secret key (EC point * scalar)
32pub fn public_mul_secret(
33    public: &mut Public, secret: &Secret,
34) -> Result<(), Error> {
35    let key_secret = secret.to_secp256k1_secret()?;
36    let mut key_public = to_secp256k1_public(public)?;
37    key_public.mul_assign(&SECP256K1, &key_secret)?;
38    set_public(public, &key_public);
39    Ok(())
40}
41
42/// Inplace add one public key to another (EC point + EC point)
43pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> {
44    let mut key_public = to_secp256k1_public(public)?;
45    let other_public = to_secp256k1_public(other)?;
46    key_public.add_assign(&SECP256K1, &other_public)?;
47    set_public(public, &key_public);
48    Ok(())
49}
50
51/// Inplace sub one public key from another (EC point - EC point)
52pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
53    let mut key_neg_other = to_secp256k1_public(other)?;
54    key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
55
56    let mut key_public = to_secp256k1_public(public)?;
57    key_public.add_assign(&SECP256K1, &key_neg_other)?;
58    set_public(public, &key_public);
59    Ok(())
60}
61
62/// Replace public key with its negation (EC point = - EC point)
63pub fn public_negate(public: &mut Public) -> Result<(), Error> {
64    let mut key_public = to_secp256k1_public(public)?;
65    key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
66    set_public(public, &key_public);
67    Ok(())
68}
69
70/// Return base point of secp256k1
71pub fn generation_point() -> Public {
72    let mut public_sec_raw = [0u8; 65];
73    public_sec_raw[0] = 4;
74    public_sec_raw[1..33].copy_from_slice(&GENERATOR_X);
75    public_sec_raw[33..65].copy_from_slice(&GENERATOR_Y);
76
77    let public_key = key::PublicKey::from_slice(&SECP256K1, &public_sec_raw)
78        .expect("constructing using predefined constants; qed");
79    let mut public = Public::default();
80    set_public(&mut public, &public_key);
81    public
82}
83
84/// Return secp256k1 elliptic curve order
85pub fn curve_order() -> U256 { H256::from_slice(&CURVE_ORDER).into_uint() }
86
87fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
88    let public_data = {
89        let mut temp = [4u8; 65];
90        (&mut temp[1..65]).copy_from_slice(&public[0..64]);
91        temp
92    };
93
94    Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?)
95}
96
97fn set_public(public: &mut Public, key_public: &key::PublicKey) {
98    let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
99    public
100        .as_bytes_mut()
101        .copy_from_slice(&key_public_serialized[1..65]);
102}
103
104#[cfg(test)]
105mod tests {
106    use super::{
107        super::{KeyPairGenerator, Random},
108        public_add, public_sub,
109    };
110
111    #[test]
112    fn public_addition_is_commutative() {
113        let public1 = Random.generate().unwrap().public().clone();
114        let public2 = Random.generate().unwrap().public().clone();
115
116        let mut left = public1.clone();
117        public_add(&mut left, &public2).unwrap();
118
119        let mut right = public2.clone();
120        public_add(&mut right, &public1).unwrap();
121
122        assert_eq!(left, right);
123    }
124
125    #[test]
126    fn public_addition_is_reversible_with_subtraction() {
127        let public1 = Random.generate().unwrap().public().clone();
128        let public2 = Random.generate().unwrap().public().clone();
129
130        let mut sum = public1.clone();
131        public_add(&mut sum, &public2).unwrap();
132        public_sub(&mut sum, &public2).unwrap();
133
134        assert_eq!(sum, public1);
135    }
136}