streaming_crypto/core_api/recovery/
checkpoint.rs1use std::any::Any;
8use digest::{array::Array, common::hazmat::SerializableState};
10use sha2::{Sha256, Sha512};
11use sha3::{Sha3_256, Sha3_512};
12use blake3::{Hasher as Blake3Hasher};
13use crate::crypto::{DigestError, digest::{DigestAlg, DigestState}};
14
15pub trait Checkpointable: Send + Sync {
16 fn export(&self) -> Vec<u8>;
17 fn segment_index(&self) -> u32;
18 fn summary(&self) -> String;
19 fn as_any(&self) -> &dyn Any;
20}
21
22#[derive(Debug, Clone)]
23pub enum SerializedState {
24 Sha256(Array<u8, <Sha256 as SerializableState>::SerializedStateSize>),
25 Sha512(Array<u8, <Sha512 as SerializableState>::SerializedStateSize>),
26 Sha3_256(Array<u8, <Sha3_256 as SerializableState>::SerializedStateSize>),
27 Sha3_512(Array<u8, <Sha3_512 as SerializableState>::SerializedStateSize>),
28 Blake3NoState,
30}
31
32impl SerializedState {
33 pub fn to_bytes(&self) -> Vec<u8> {
34 match self {
35 SerializedState::Sha256(arr) => arr.to_vec(),
36 SerializedState::Sha512(arr) => arr.to_vec(),
37 SerializedState::Sha3_256(arr) => arr.to_vec(),
38 SerializedState::Sha3_512(arr) => arr.to_vec(),
39 SerializedState::Blake3NoState => Vec::new(),
40 }
41 }
42}
43
44#[derive(Debug, Clone)]
45pub struct SegmentCheckpoint {
46 pub alg: DigestAlg,
47 pub segment_index: u32,
48 pub next_frame_index: u32,
49 pub state: SerializedState,
50}
51
52impl SegmentCheckpoint {
53 pub fn from_state(alg: DigestAlg, segment_index: u32, next_frame_index: u32, state: &DigestState) -> Self {
54 let state = match state {
55 DigestState::Sha256(h) => SerializedState::Sha256(h.serialize()),
56 DigestState::Sha512(h) => SerializedState::Sha512(h.serialize()),
57 DigestState::Sha3_256(h) => SerializedState::Sha3_256(h.serialize()),
58 DigestState::Sha3_512(h) => SerializedState::Sha3_512(h.serialize()),
59 DigestState::Blake3(_) => SerializedState::Blake3NoState,
61 };
62 Self { alg, segment_index, next_frame_index, state }
63 }
64 pub fn resume_from_checkpoint(self) -> Result<DigestState, DigestError> {
65 match (self.alg, self.state) {
66 (DigestAlg::Sha256, SerializedState::Sha256(arr)) => Sha256::deserialize(&arr).map(DigestState::Sha256).map_err(|_| DigestError::InvalidFormat),
67 (DigestAlg::Sha512, SerializedState::Sha512(arr)) => Sha512::deserialize(&arr).map(DigestState::Sha512).map_err(|_| DigestError::InvalidFormat),
68 (DigestAlg::Sha3_256, SerializedState::Sha3_256(arr)) => Sha3_256::deserialize(&arr).map(DigestState::Sha3_256).map_err(|_| DigestError::InvalidFormat),
69 (DigestAlg::Sha3_512, SerializedState::Sha3_512(arr)) => Sha3_512::deserialize(&arr).map(DigestState::Sha3_512).map_err(|_| DigestError::InvalidFormat),
70 (DigestAlg::Blake3, _) => Ok(DigestState::Blake3(Blake3Hasher::new())),
73 _ => Err(DigestError::InvalidFormat),
74 }
75 }
76
77}
78
79impl Checkpointable for SegmentCheckpoint {
80 fn export(&self) -> Vec<u8> { self.state.to_bytes() }
81 fn segment_index(&self) -> u32 { self.segment_index }
82 fn summary(&self) -> String { format!("SegmentCheckpoint: alg={:?}, segment={}, next={}", self.alg, self.segment_index, self.next_frame_index) }
83 fn as_any(&self) -> &dyn Any { self }
84}
85
86#[derive(Debug, Clone)]
89pub enum DecryptState {
90 AesCtr([u8; 16]),
91 ChaCha20([u8; 32]),
92}
93
94impl DecryptState {
95 pub fn to_bytes(&self) -> Vec<u8> {
96 match self {
97 DecryptState::AesCtr(arr) => arr.to_vec(),
98 DecryptState::ChaCha20(arr) => arr.to_vec(),
99 }
100 }
101 pub fn from_bytes(alg_type: &str, bytes: &[u8]) -> Option<Self> {
102 match alg_type {
103 "AesCtr" if bytes.len() == 16 => Some(DecryptState::AesCtr(bytes.try_into().ok()?)),
104 "ChaCha20" if bytes.len() == 32 => Some(DecryptState::ChaCha20(bytes.try_into().ok()?)),
105 _ => None,
106 }
107 }
108}
109
110pub struct DecryptCheckpoint {
111 pub segment_index: u32,
112 pub frame_index: u32,
113 pub state: DecryptState,
114}
115
116impl Checkpointable for DecryptCheckpoint {
117 fn export(&self) -> Vec<u8> { self.state.to_bytes() }
118 fn segment_index(&self) -> u32 { self.segment_index }
119 fn summary(&self) -> String { format!("DecryptCheckpoint: segment={}, frame={}", self.segment_index, self.frame_index) }
120 fn as_any(&self) -> &dyn Any { self }
121}