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]; const DILITHIUM3_MAGIC_BYTES: [u8; 4] = [211, 12, 0, 0]; #[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 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}