wildland_crypto/identity/
signing_keypair.rs

1//
2// Wildland Project
3//
4// Copyright © 2022 Golem Foundation
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License version 3 as published by
8// the Free Software Foundation.
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 ed25519_dalek::{Keypair, PublicKey, SecretKey, Signer};
19use rand::{CryptoRng, RngCore};
20use serde::{Deserialize, Serialize};
21
22use super::bytes_key_from_str;
23use crate::error::CryptoError;
24use crate::signature::Signature;
25
26pub type PubKey = [u8; 32];
27pub type SecKey = [u8; 32];
28
29#[derive(Debug)]
30pub struct SigningKeypair(ed25519_dalek::Keypair);
31
32impl<'de> Deserialize<'de> for SigningKeypair {
33    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
34    where
35        D: serde::Deserializer<'de>,
36    {
37        let hex_encoded_str = String::deserialize(deserializer)?;
38        let bytes = hex::decode(hex_encoded_str).map_err(serde::de::Error::custom)?;
39        Ok(Self(
40            ed25519_dalek::Keypair::from_bytes(&bytes).map_err(serde::de::Error::custom)?,
41        ))
42    }
43}
44
45impl Serialize for SigningKeypair {
46    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47    where
48        S: serde::Serializer,
49    {
50        let hex = hex::encode(self.0.to_bytes());
51        String::serialize(&hex, serializer)
52    }
53}
54
55impl TryFrom<Vec<u8>> for SigningKeypair {
56    type Error = CryptoError;
57
58    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
59        Ok(Self(
60            ed25519_dalek::Keypair::from_bytes(value.as_slice())
61                .map_err(|e| CryptoError::InvalidSignatureBytesError(e.to_string()))?,
62        ))
63    }
64}
65
66impl PartialEq for SigningKeypair {
67    fn eq(&self, other: &Self) -> bool {
68        self.public() == other.public() && self.secret() == other.secret()
69    }
70}
71
72impl From<&SigningKeypair> for SigningKeypair {
73    fn from(other: &SigningKeypair) -> Self {
74        Self(ed25519_dalek::Keypair {
75            public: PublicKey::from_bytes(&other.public()).unwrap(),
76            secret: SecretKey::from_bytes(&other.secret()).unwrap(),
77        })
78    }
79}
80
81impl SigningKeypair {
82    pub fn generate<R>(csprng: &mut R) -> Self
83    where
84        R: CryptoRng + RngCore,
85    {
86        //TODO: WILX-366 use ed25519_dalek::Keypair::generate(csprng) when ed25519_dalek will support rand 0.8
87
88        let mut bytes = [0u8; 32];
89        csprng.fill_bytes(&mut bytes);
90
91        let sk = SecretKey::from_bytes(bytes.as_ref()).unwrap();
92
93        Self(Keypair {
94            public: (&sk).into(),
95            secret: sk,
96        })
97    }
98
99    pub fn try_from_bytes_slices(pubkey: PubKey, seckey: SecKey) -> Result<Self, CryptoError> {
100        Ok(Self(
101            ed25519_dalek::Keypair::from_bytes([seckey, pubkey].concat().as_slice())
102                .map_err(|e| CryptoError::InvalidSignatureBytesError(e.to_string()))?,
103        ))
104    }
105
106    pub fn try_from_str(public_key: &str, secret_key: &str) -> Result<Self, CryptoError> {
107        let pubkey = bytes_key_from_str(public_key)?;
108        let seckey = bytes_key_from_str(secret_key)?;
109        Self::try_from_bytes_slices(pubkey, seckey)
110    }
111
112    pub fn try_from_secret_bytes(secret_key_bytes: &SecKey) -> Result<Self, CryptoError> {
113        let sec_key = ed25519_dalek::SecretKey::from_bytes(secret_key_bytes)
114            .map_err(|e| CryptoError::InvalidSignatureBytesError(e.to_string()))?;
115        let pub_key = ed25519_dalek::PublicKey::from(&sec_key);
116        Ok(Self(ed25519_dalek::Keypair {
117            secret: sec_key,
118            public: pub_key,
119        }))
120    }
121
122    pub fn public(&self) -> PubKey {
123        self.0.public.to_bytes()
124    }
125
126    pub fn secret(&self) -> SecKey {
127        self.0.secret.to_bytes()
128    }
129
130    pub fn to_bytes(&self) -> Vec<u8> {
131        Vec::from(self.0.to_bytes())
132    }
133
134    pub fn sign(&self, msg: &[u8]) -> Signature {
135        Signature(self.0.sign(msg))
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use crate::common::test_utilities::{SIGNING_PUBLIC_KEY, SIGNING_SECRET_KEY};
142    use crate::identity::signing_keypair::SigningKeypair;
143
144    #[test]
145    fn should_create_keypair_when_keys_have_proper_length() {
146        // when
147        let keypair = SigningKeypair::try_from_str(SIGNING_PUBLIC_KEY, SIGNING_SECRET_KEY);
148
149        // then
150        assert!(keypair.is_ok());
151    }
152
153    #[test]
154    fn should_not_create_keypair_when_pub_key_is_too_short() {
155        // when
156        let keypair = SigningKeypair::try_from_str("", SIGNING_SECRET_KEY);
157
158        // then
159        assert!(keypair.is_err());
160    }
161
162    #[test]
163    fn should_not_create_keypair_when_pub_key_is_too_long() {
164        // when
165        let keypair = SigningKeypair::try_from_str(
166            "1234567890123456789012345678901234567890123456789012345678901234567890",
167            SIGNING_SECRET_KEY,
168        );
169
170        // then
171        assert!(keypair.is_err());
172    }
173
174    #[test]
175    fn should_not_create_keypair_when_sec_key_is_too_short() {
176        // when
177        let keypair = SigningKeypair::try_from_str(SIGNING_PUBLIC_KEY, "");
178
179        // then
180        assert!(keypair.is_err());
181    }
182
183    #[test]
184    fn should_not_create_keypair_when_sec_key_is_too_long() {
185        // when
186        let keypair = SigningKeypair::try_from_str(
187            SIGNING_PUBLIC_KEY,
188            "1234567890123456789012345678901234567890123456789012345678901234567890",
189        );
190
191        // then
192        assert!(keypair.is_err());
193    }
194}