chie_crypto/
forward_secure.rs1use crate::signing::{KeyPair, PublicKey, verify as signing_verify};
56use blake3::Hasher;
57use serde::{Deserialize, Serialize};
58use thiserror::Error;
59use zeroize::Zeroize;
60
61#[derive(Error, Debug)]
62pub enum ForwardSecureError {
63 #[error("Maximum time period reached")]
64 MaxPeriodReached,
65 #[error("Invalid signature")]
66 InvalidSignature,
67 #[error("Period mismatch: signature period {sig_period} != expected {expected_period}")]
68 PeriodMismatch {
69 sig_period: u64,
70 expected_period: u64,
71 },
72 #[error("Serialization error: {0}")]
73 Serialization(String),
74 #[error("Key evolution error")]
75 EvolutionError,
76}
77
78pub type ForwardSecureResult<T> = Result<T, ForwardSecureError>;
79
80#[derive(Clone, Serialize, Deserialize)]
82pub struct ForwardSecureSignature {
83 signature: Vec<u8>,
85 period: u64,
87}
88
89impl ForwardSecureSignature {
90 pub fn period(&self) -> u64 {
92 self.period
93 }
94
95 pub fn verify(
97 &self,
98 message: &[u8],
99 public_key: &ForwardSecurePublicKey,
100 ) -> ForwardSecureResult<()> {
101 let period_pubkey = public_key.derive_period_key(self.period);
103
104 if self.signature.len() != 64 {
106 return Err(ForwardSecureError::InvalidSignature);
107 }
108 let mut sig_bytes = [0u8; 64];
109 sig_bytes.copy_from_slice(&self.signature);
110
111 signing_verify(&period_pubkey, message, &sig_bytes)
113 .map_err(|_| ForwardSecureError::InvalidSignature)?;
114
115 Ok(())
116 }
117
118 pub fn to_bytes(&self) -> ForwardSecureResult<Vec<u8>> {
120 crate::codec::encode(self).map_err(|e| ForwardSecureError::Serialization(e.to_string()))
121 }
122
123 pub fn from_bytes(bytes: &[u8]) -> ForwardSecureResult<Self> {
125 crate::codec::decode(bytes).map_err(|e| ForwardSecureError::Serialization(e.to_string()))
126 }
127}
128
129#[derive(Clone, Serialize, Deserialize)]
131pub struct ForwardSecurePublicKey {
132 base_pubkey: PublicKey,
134 max_periods: u64,
136}
137
138impl ForwardSecurePublicKey {
139 fn derive_period_key(&self, _period: u64) -> PublicKey {
141 self.base_pubkey
144 }
145
146 pub fn max_periods(&self) -> u64 {
148 self.max_periods
149 }
150
151 pub fn to_bytes(&self) -> ForwardSecureResult<Vec<u8>> {
153 crate::codec::encode(self).map_err(|e| ForwardSecureError::Serialization(e.to_string()))
154 }
155
156 pub fn from_bytes(bytes: &[u8]) -> ForwardSecureResult<Self> {
158 crate::codec::decode(bytes).map_err(|e| ForwardSecureError::Serialization(e.to_string()))
159 }
160}
161
162struct ForwardSecureSecretKey {
164 current_key: KeyPair,
166 evolution_seed: [u8; 32],
168}
169
170impl Drop for ForwardSecureSecretKey {
171 fn drop(&mut self) {
172 self.evolution_seed.zeroize();
175 }
176}
177
178pub struct ForwardSecureKeypair {
180 secret: ForwardSecureSecretKey,
182 public: ForwardSecurePublicKey,
184 current_period: u64,
186 max_periods: u64,
188}
189
190impl ForwardSecureKeypair {
191 pub fn generate(max_periods: u64) -> Self {
196 use rand::RngCore;
197
198 let mut evolution_seed = [0u8; 32];
199 rand::rngs::OsRng.fill_bytes(&mut evolution_seed);
200
201 let current_key = KeyPair::generate();
203 let base_pubkey = current_key.public_key();
204
205 Self {
206 secret: ForwardSecureSecretKey {
207 current_key,
208 evolution_seed,
209 },
210 public: ForwardSecurePublicKey {
211 base_pubkey,
212 max_periods,
213 },
214 current_period: 0,
215 max_periods,
216 }
217 }
218
219 pub fn sign(&self, message: &[u8]) -> ForwardSecureResult<ForwardSecureSignature> {
221 let signature = self.secret.current_key.sign(message);
222
223 Ok(ForwardSecureSignature {
224 signature: signature.to_vec(),
225 period: self.current_period,
226 })
227 }
228
229 pub fn evolve(&mut self) -> ForwardSecureResult<()> {
236 if self.current_period >= self.max_periods - 1 {
237 return Err(ForwardSecureError::MaxPeriodReached);
238 }
239
240 let mut hasher = Hasher::new();
242 hasher.update(&self.secret.evolution_seed);
243 hasher.update(&self.current_period.to_le_bytes());
244 let new_seed = hasher.finalize();
245
246 self.secret
248 .evolution_seed
249 .copy_from_slice(new_seed.as_bytes());
250
251 self.secret.current_key = KeyPair::generate();
254
255 self.current_period += 1;
257
258 Ok(())
259 }
260
261 pub fn current_period(&self) -> u64 {
263 self.current_period
264 }
265
266 pub fn public_key(&self) -> &ForwardSecurePublicKey {
268 &self.public
269 }
270
271 pub fn max_periods(&self) -> u64 {
273 self.max_periods
274 }
275}
276
277pub struct ForwardSecureBuilder {
279 max_periods: u64,
280 initial_period: u64,
281}
282
283impl ForwardSecureBuilder {
284 pub fn new() -> Self {
286 Self {
287 max_periods: 1000,
288 initial_period: 0,
289 }
290 }
291
292 pub fn max_periods(mut self, max_periods: u64) -> Self {
294 self.max_periods = max_periods;
295 self
296 }
297
298 pub fn initial_period(mut self, period: u64) -> Self {
300 self.initial_period = period;
301 self
302 }
303
304 pub fn build(self) -> ForwardSecureKeypair {
306 let mut keypair = ForwardSecureKeypair::generate(self.max_periods);
307 keypair.current_period = self.initial_period;
308 keypair
309 }
310}
311
312impl Default for ForwardSecureBuilder {
313 fn default() -> Self {
314 Self::new()
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn test_forward_secure_basic() {
324 let keypair = ForwardSecureKeypair::generate(10);
325 let public_key = keypair.public_key().clone();
326
327 let message = b"test message";
328 let sig = keypair.sign(message).unwrap();
329
330 assert_eq!(sig.period(), 0);
331 assert!(sig.verify(message, &public_key).is_ok());
332 }
333
334 #[test]
335 fn test_key_evolution() {
336 let mut keypair = ForwardSecureKeypair::generate(10);
337 let public_key = keypair.public_key().clone();
338
339 let msg0 = b"message in period 0";
341 let sig0 = keypair.sign(msg0).unwrap();
342 assert_eq!(sig0.period(), 0);
343
344 assert!(sig0.verify(msg0, &public_key).is_ok());
346
347 keypair.evolve().unwrap();
349 assert_eq!(keypair.current_period(), 1);
350
351 let msg1 = b"message in period 1";
353 let sig1 = keypair.sign(msg1).unwrap();
354 assert_eq!(sig1.period(), 1);
355
356 }
359
360 #[test]
361 fn test_multiple_evolutions() {
362 let mut keypair = ForwardSecureKeypair::generate(5);
363
364 for i in 0..5 {
366 assert_eq!(keypair.current_period(), i);
367
368 let msg = format!("message {}", i).into_bytes();
370 let sig = keypair.sign(&msg).unwrap();
371 assert_eq!(sig.period(), i);
372
373 if i < 4 {
374 keypair.evolve().unwrap();
375 }
376 }
377
378 assert_eq!(keypair.current_period(), 4);
380 }
381
382 #[test]
383 fn test_max_period_reached() {
384 let mut keypair = ForwardSecureKeypair::generate(3);
385
386 keypair.evolve().unwrap(); keypair.evolve().unwrap(); assert!(keypair.evolve().is_err());
392 }
393
394 #[test]
395 fn test_wrong_message_fails() {
396 let keypair = ForwardSecureKeypair::generate(10);
397 let public_key = keypair.public_key().clone();
398
399 let sig = keypair.sign(b"original").unwrap();
400 assert!(sig.verify(b"tampered", &public_key).is_err());
401 }
402
403 #[test]
404 fn test_signature_serialization() {
405 let keypair = ForwardSecureKeypair::generate(10);
406 let sig = keypair.sign(b"test").unwrap();
407
408 let bytes = sig.to_bytes().unwrap();
409 let deserialized = ForwardSecureSignature::from_bytes(&bytes).unwrap();
410
411 assert_eq!(sig.period(), deserialized.period());
412 }
413
414 #[test]
415 fn test_public_key_serialization() {
416 let keypair = ForwardSecureKeypair::generate(10);
417 let public_key = keypair.public_key();
418
419 let bytes = public_key.to_bytes().unwrap();
420 let deserialized = ForwardSecurePublicKey::from_bytes(&bytes).unwrap();
421
422 assert_eq!(public_key.max_periods(), deserialized.max_periods());
423 }
424
425 #[test]
426 fn test_builder_default() {
427 let keypair = ForwardSecureBuilder::default().build();
428 assert_eq!(keypair.current_period(), 0);
429 assert_eq!(keypair.max_periods(), 1000);
430 }
431
432 #[test]
433 fn test_builder_custom_periods() {
434 let keypair = ForwardSecureBuilder::new().max_periods(50).build();
435 assert_eq!(keypair.max_periods(), 50);
436 }
437
438 #[test]
439 fn test_builder_initial_period() {
440 let keypair = ForwardSecureBuilder::new()
441 .max_periods(100)
442 .initial_period(5)
443 .build();
444 assert_eq!(keypair.current_period(), 5);
445 }
446
447 #[test]
448 fn test_period_independence() {
449 let keypair1 = ForwardSecureKeypair::generate(10);
450 let keypair2 = ForwardSecureKeypair::generate(10);
451
452 let msg = b"test";
453
454 let sig1 = keypair1.sign(msg).unwrap();
456 let sig2 = keypair2.sign(msg).unwrap();
457
458 assert!(sig1.verify(msg, keypair1.public_key()).is_ok());
460 assert!(sig2.verify(msg, keypair2.public_key()).is_ok());
461 }
462
463 #[test]
464 fn test_deterministic_evolution() {
465 let mut keypair = ForwardSecureKeypair::generate(10);
466
467 let period0 = keypair.current_period();
468 keypair.evolve().unwrap();
469 let period1 = keypair.current_period();
470 keypair.evolve().unwrap();
471 let period2 = keypair.current_period();
472
473 assert_eq!(period0, 0);
474 assert_eq!(period1, 1);
475 assert_eq!(period2, 2);
476 }
477
478 #[test]
479 fn test_public_key_max_periods() {
480 let keypair = ForwardSecureKeypair::generate(42);
481 assert_eq!(keypair.public_key().max_periods(), 42);
482 }
483}