Skip to main content

laron_crypto/
public_key.rs

1// This file is part of the laron-crypto
2//
3// Copyright 2023 Ade M Ramdani
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18use crate::error::{Error, Result};
19use constant_time_eq::constant_time_eq;
20use k256::elliptic_curve::group::prime::PrimeCurveAffine;
21use k256::elliptic_curve::sec1::ToEncodedPoint;
22use k256::{AffinePoint, NonZeroScalar};
23
24/// Byte size of the public key
25const SIZE: usize = 65;
26
27/// Public key
28#[derive(Debug, Clone, Copy)]
29pub struct PublicKey {
30    bytes: [u8; SIZE],
31}
32
33impl PartialEq for PublicKey {
34    fn eq(&self, other: &Self) -> bool {
35        constant_time_eq(&self.bytes, &other.bytes)
36    }
37}
38
39impl Eq for PublicKey {}
40
41impl PublicKey {
42    /// Create public key from bytes
43    pub fn from_bytes(bytes: [u8; SIZE]) -> Self {
44        Self { bytes }
45    }
46
47    /// Create public key from slice
48    pub fn from_slice(slice: &[u8]) -> Result<Self> {
49        if slice.len() != SIZE {
50            Err(Error::LengthError(format!(
51                "PublicKey size must be {} bytes got {} bytes.",
52                SIZE,
53                slice.len()
54            )))
55        } else {
56            let mut new_bytes = [0u8; SIZE];
57            new_bytes.copy_from_slice(slice);
58            Ok(Self::from_bytes(new_bytes))
59        }
60    }
61
62    /// Create public key from hex string
63    pub fn from_hex(hex: &str) -> Result<Self> {
64        if hex.len() != SIZE * 2 {
65            Err(Error::LengthError(format!(
66                "PublicKey hex must be {} characters got {} characters.",
67                SIZE * 2,
68                hex.len()
69            )))
70        } else {
71            let bytes = hex::decode(hex)?;
72            Self::from_slice(&bytes)
73        }
74    }
75
76    /// Get public key as bytes
77    pub fn as_bytes(&self) -> [u8; SIZE] {
78        self.bytes
79    }
80
81    /// Get public key as compressed bytes
82    pub fn as_compressed_bytes(&self) -> [u8; 33] {
83        let pk = k256::PublicKey::from_sec1_bytes(&self.bytes).unwrap();
84        let bytes = pk.to_encoded_point(true);
85        bytes.as_bytes().try_into().unwrap()
86    }
87
88    /// Get public key as slice
89    pub fn as_slice(&self) -> &[u8] {
90        &self.bytes
91    }
92
93    /// Get public key as hex string
94    pub fn as_hex(&self) -> String {
95        hex::encode(&self.bytes)
96    }
97
98    /// Derive child key from parent key.
99    pub fn derive_child(&self, other: [u8; 32]) -> Result<Self> {
100        let current = k256::PublicKey::from_sec1_bytes(&self.bytes).unwrap();
101        let child_scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
102            .ok_or(Error::InvalidPublicKey)?;
103        let child_point = current.to_projective() + (AffinePoint::generator() * *child_scalar);
104        let derived = k256::PublicKey::from_affine(child_point.into())
105            .map_err(|_| Error::InvalidPublicKey)?;
106        let bytes = derived.to_encoded_point(false);
107        Self::from_slice(bytes.as_bytes())
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use crate::PrivateKey;
114
115    use super::*;
116
117    #[test]
118    fn test_public_key() {
119        let key = PrivateKey::new();
120        let pk = key.public_key();
121        let pk_bytes = pk.as_bytes();
122        let pk_hex = pk.as_hex();
123        let pk_slice = pk.as_slice();
124        let pk_compressed = pk.as_compressed_bytes();
125        assert_eq!(pk_bytes.len(), SIZE);
126        assert_eq!(pk_hex.len(), SIZE * 2);
127        assert_eq!(pk_slice.len(), SIZE);
128        assert_eq!(pk_compressed.len(), 33);
129        assert_eq!(pk, PublicKey::from_slice(pk_slice).unwrap());
130        assert_eq!(pk, PublicKey::from_hex(&pk_hex).unwrap());
131    }
132}