sare_core/hybrid_sign/
mod.rs

1pub mod error;
2
3use crate::hybrid_sign::error::*;
4use crate::seed::Seed;
5use crystals_dilithium as dilithium;
6use ed25519_compact as ed25519;
7use secrecy::{ExposeSecret, SecretVec};
8
9use serde::{Deserialize, Serialize};
10use sha2::Digest;
11
12const ED25519_MAGIC_BYTES: [u8; 4] = [25, 85, 210, 14]; // 0xED25519 in LittleEndian
13const DILITHIUM3_MAGIC_BYTES: [u8; 4] = [211, 12, 0, 0]; // 0xCD3 in LittleEndian
14
15#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
16pub enum ECAlgorithm {
17    Ed25519,
18}
19
20impl ToString for ECAlgorithm {
21    fn to_string(&self) -> String {
22        match self {
23            Self::Ed25519 => String::from("Ed25519"),
24        }
25    }
26}
27
28pub struct ECKeyPair {
29    pub public_key: Vec<u8>,
30    pub secret_key: SecretVec<u8>,
31    pub algorithm: ECAlgorithm,
32}
33
34impl ECKeyPair {
35    pub fn from_secret_key(
36        secret_key: &SecretVec<u8>,
37        ec_algorithm: ECAlgorithm,
38    ) -> Result<Self, HybridSignError> {
39        match ec_algorithm {
40            ECAlgorithm::Ed25519 => {
41                let secret_key = ed25519::SecretKey::from_slice(secret_key.expose_secret())?;
42                let public_key = secret_key.public_key();
43
44                Ok(ECKeyPair {
45                    public_key: public_key.to_vec(),
46                    secret_key: SecretVec::from(secret_key.to_vec()),
47                    algorithm: ec_algorithm,
48                })
49            }
50        }
51    }
52
53    pub fn from_seed(seed: &Seed, ec_algorithm: ECAlgorithm) -> Self {
54        match ec_algorithm {
55            ECAlgorithm::Ed25519 => {
56                let child_seed = seed.derive_32bytes_child_seed(Some(&ED25519_MAGIC_BYTES));
57                let keypair = ed25519::KeyPair::from_seed(
58                    ed25519::Seed::from_slice(child_seed.expose_secret()).unwrap(),
59                );
60
61                ECKeyPair {
62                    public_key: keypair.pk.to_vec(),
63                    secret_key: SecretVec::from(keypair.sk.to_vec()),
64                    algorithm: ec_algorithm,
65                }
66            }
67        }
68    }
69}
70
71pub struct ECSignature<'a> {
72    pub keypair: &'a ECKeyPair,
73}
74
75impl<'a> ECSignature<'a> {
76    pub fn new(keypair: &'a ECKeyPair) -> Self {
77        ECSignature { keypair }
78    }
79
80    pub fn sign(&self, message: &[u8]) -> Vec<u8> {
81        let signature_algorithm = &self.keypair.algorithm;
82
83        match signature_algorithm {
84            ECAlgorithm::Ed25519 => {
85                let secret_key =
86                    ed25519::SecretKey::from_slice(self.keypair.secret_key.expose_secret())
87                        .unwrap();
88                let signature = secret_key.sign(message, Some(ed25519::Noise::generate()));
89                signature.to_vec()
90            }
91        }
92    }
93
94    pub fn verify(
95        signature_algorithm: &ECAlgorithm,
96        public_key: &[u8],
97        message: &[u8],
98        signature: &[u8],
99    ) -> Result<bool, HybridSignError> {
100        match signature_algorithm {
101            ECAlgorithm::Ed25519 => {
102                let public_key = ed25519::PublicKey::from_slice(public_key)?;
103                let signature = ed25519::Signature::from_slice(signature)?;
104                let does_verify = public_key.verify(message, &signature);
105
106                Ok(does_verify.is_ok())
107            }
108        }
109    }
110
111    fn hash_message(message: &[u8]) -> Vec<u8> {
112        let mut hasher = sha3::Sha3_256::new();
113
114        hasher.update(message);
115
116        let result = hasher.finalize();
117
118        result.to_vec()
119    }
120
121    pub fn hash_and_sign(&self, message: &[u8]) -> Vec<u8> {
122        self.sign(&Self::hash_message(message))
123    }
124
125    pub fn hash_and_verify(
126        signature_algorithm: &ECAlgorithm,
127        public_key: &[u8],
128        message: &[u8],
129        signature: &[u8],
130    ) -> Result<bool, HybridSignError> {
131        Self::verify(
132            signature_algorithm,
133            public_key,
134            &Self::hash_message(message),
135            signature,
136        )
137    }
138}
139
140#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
141pub enum PQAlgorithm {
142    Dilithium3,
143}
144
145impl ToString for PQAlgorithm {
146    fn to_string(&self) -> String {
147        match self {
148            Self::Dilithium3 => String::from("Dilithium3"),
149        }
150    }
151}
152
153pub struct PQKeyPair {
154    pub public_key: Vec<u8>,
155    pub secret_key: SecretVec<u8>,
156    pub algorithm: PQAlgorithm,
157}
158
159impl PQKeyPair {
160    pub fn from_seed(seed: &Seed, pq_algorithm: PQAlgorithm) -> Self {
161        match pq_algorithm {
162            PQAlgorithm::Dilithium3 => {
163                let child_seed = seed.derive_32bytes_child_seed(Some(&DILITHIUM3_MAGIC_BYTES));
164                let keypair =
165                    dilithium::dilithium3::Keypair::generate(Some(child_seed.expose_secret()));
166                PQKeyPair {
167                    public_key: keypair.public.to_bytes().to_vec(),
168                    secret_key: SecretVec::from(keypair.secret.to_bytes().to_vec()),
169                    algorithm: pq_algorithm,
170                }
171            }
172        }
173    }
174}
175
176pub struct PQSignature<'a> {
177    pub keypair: &'a PQKeyPair,
178}
179
180impl<'a> PQSignature<'a> {
181    //TODO: Implement hash_and_sign function using HMAC and sha3
182
183    pub fn new(keypair: &'a PQKeyPair) -> Self {
184        PQSignature { keypair }
185    }
186
187    fn hash_message(message: &[u8]) -> Vec<u8> {
188        let mut hasher = sha3::Sha3_256::new();
189
190        hasher.update(message);
191
192        let result = hasher.finalize();
193
194        result.to_vec()
195    }
196
197    pub fn hash_and_sign(&self, message: &[u8]) -> Vec<u8> {
198        self.sign(&Self::hash_message(message))
199    }
200
201    pub fn hash_and_verify(
202        signature_algorithm: &PQAlgorithm,
203        public_key: &[u8],
204        message: &[u8],
205        signature: &[u8],
206    ) -> Result<bool, HybridSignError> {
207        Self::verify(
208            signature_algorithm,
209            public_key,
210            &Self::hash_message(message),
211            signature,
212        )
213    }
214
215    pub fn sign(&self, message: &[u8]) -> Vec<u8> {
216        let signature_algorithm = &self.keypair.algorithm;
217
218        match signature_algorithm {
219            PQAlgorithm::Dilithium3 => {
220                let secret_key = dilithium::dilithium3::SecretKey::from_bytes(
221                    self.keypair.secret_key.expose_secret(),
222                );
223
224                let signature = secret_key.sign(message);
225
226                signature.to_vec()
227            }
228        }
229    }
230
231    pub fn verify(
232        signature_algorithm: &PQAlgorithm,
233        public_key: &[u8],
234        message: &[u8],
235        signature: &[u8],
236    ) -> Result<bool, HybridSignError> {
237        match signature_algorithm {
238            PQAlgorithm::Dilithium3 => {
239                let public_key = dilithium::dilithium3::PublicKey::from_bytes(public_key);
240
241                let does_verify = public_key.verify(message, signature);
242
243                Ok(does_verify)
244            }
245        }
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use base64::prelude::*;
253
254    const TEST_SEED: [u8; 128] = [
255        198, 44, 204, 124, 44, 49, 54, 122, 236, 122, 174, 6, 50, 107, 65, 214, 47, 51, 12, 251,
256        107, 231, 10, 176, 23, 212, 180, 156, 17, 59, 207, 193, 239, 137, 69, 61, 25, 4, 0, 233,
257        97, 31, 94, 200, 222, 243, 222, 181, 63, 225, 246, 49, 233, 246, 206, 13, 147, 85, 137, 5,
258        165, 80, 188, 150, 198, 44, 204, 124, 44, 49, 54, 122, 236, 122, 174, 6, 50, 107, 65, 214,
259        47, 51, 12, 251, 107, 231, 10, 176, 23, 212, 180, 156, 17, 59, 207, 193, 239, 137, 69, 61,
260        25, 4, 0, 233, 97, 31, 94, 200, 222, 243, 222, 181, 63, 225, 246, 49, 233, 246, 206, 13,
261        147, 85, 137, 5, 165, 80, 188, 150,
262    ];
263
264    const ED25519_SECRET_KEY: &str =
265        "pVgbNU6QXuHBvsCKHZHE4yrViux9PCUf5XMznd9MYBNyVnUzMutKA/o7/WgEtu5P+aJWJ3MxXLyq+VvnwKC/ew==";
266
267    const ED25519_PUBLIC_KEY: &str = "clZ1MzLrSgP6O/1oBLbuT/miVidzMVy8qvlb58Cgv3s=";
268    const ED25519_SIGNATURE: &str =
269        "fwzNIUJZdlUfd81dyxFhpRU1ePtnhx3KuQzaUYRmYfc5vkU1S+7cgI/A9v7W7jE1SNp1DpX2YwF8K3Ef0RujCA==";
270
271    #[test]
272    fn ed25519_keypair_from_seed() {
273        let keypair = ECKeyPair::from_seed(
274            &Seed::new(SecretVec::from(TEST_SEED.to_vec())),
275            ECAlgorithm::Ed25519,
276        );
277
278        assert_eq!(
279            BASE64_STANDARD.encode(keypair.secret_key.expose_secret()),
280            ED25519_SECRET_KEY,
281        );
282        assert_eq!(
283            BASE64_STANDARD.encode(keypair.public_key),
284            ED25519_PUBLIC_KEY,
285        );
286    }
287
288    #[test]
289    fn ed25519_keypair_from_secret_key() {
290        let keypair = ECKeyPair::from_secret_key(
291            &SecretVec::from(BASE64_STANDARD.decode(ED25519_SECRET_KEY).unwrap()),
292            ECAlgorithm::Ed25519,
293        )
294        .unwrap();
295
296        assert_eq!(
297            BASE64_STANDARD.encode(keypair.public_key),
298            ED25519_PUBLIC_KEY
299        );
300    }
301
302    #[test]
303    fn ed25519_sign() {
304        assert!(
305            ECSignature::verify(
306                &ECAlgorithm::Ed25519,
307                &BASE64_STANDARD.decode(ED25519_PUBLIC_KEY).unwrap(),
308                b"SARE",
309                &BASE64_STANDARD.decode(ED25519_SIGNATURE).unwrap()
310            )
311            .unwrap()
312        );
313    }
314}