object_rainbow_encrypted_store/
lib.rs1use object_rainbow::{DiffHashes, ToOutput, WithHash};
2use object_rainbow_encrypted::Key;
3use object_rainbow_store::ExternalStore;
4
5#[derive(Clone, PartialEq)]
6pub struct EncryptedStore<S, K> {
7 store: S,
8 key: K,
9}
10
11impl<S, K> EncryptedStore<S, K> {
12 pub fn new(store: S, key: K) -> Self {
13 Self { store, key }
14 }
15}
16
17impl<S: ExternalStore, K: Key> ExternalStore for EncryptedStore<S, K> {
18 type Id = S::Id;
19
20 async fn save_data(
21 &self,
22 data: &[u8],
23 refs: &[Self::Id],
24 wh: WithHash<'_, impl ToOutput>,
25 ) -> object_rainbow::Result<Self::Id> {
26 let encrypted = &self.key.encrypt(data);
27 let diff = DiffHashes {
28 tags: Default::default(),
29 topology: refs.data_hash(),
30 mangle: (self.key.mangle_prefix().data_hash(), wh.data.data_hash()).data_hash(),
31 };
32 self.store
33 .save_data(
34 encrypted,
35 refs,
36 WithHash {
37 diff: diff.data_hash(),
38 data: encrypted,
39 },
40 )
41 .await
42 }
43
44 async fn contains_data(
45 &self,
46 data: &[u8],
47 refs: &[Self::Id],
48 wh: WithHash<'_, impl Send + Sync + ToOutput>,
49 ) -> object_rainbow::Result<bool> {
50 let encrypted = &self.key.encrypt(data);
51 let diff = DiffHashes {
52 tags: Default::default(),
53 topology: refs.data_hash(),
54 mangle: (self.key.mangle_prefix().data_hash(), wh.data.data_hash()).data_hash(),
55 };
56 self.store
57 .contains_data(
58 encrypted,
59 refs,
60 WithHash {
61 diff: diff.data_hash(),
62 data: encrypted,
63 },
64 )
65 .await
66 }
67
68 async fn contains(&self, id: &Self::Id) -> object_rainbow::Result<bool> {
69 self.store.contains(id).await
70 }
71
72 #[expect(refining_impl_trait)]
73 async fn fetch(&self, id: &Self::Id) -> object_rainbow::Result<Vec<u8>> {
74 self.key
75 .decrypt(self.store.fetch(id).await?.as_ref())
76 .map_err(object_rainbow::Error::consistency)
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use std::convert::Infallible;
83
84 use macro_rules_attribute::apply;
85 use object_rainbow::{FullHash, Hash, ToOutput, WithHash};
86 use object_rainbow_encrypted::{Key, encrypt};
87 use object_rainbow_point::IntoPoint;
88 use object_rainbow_store::ExternalStore;
89 use smol_macros::test;
90
91 use crate::EncryptedStore;
92
93 #[derive(Clone, PartialEq)]
94 struct NormalStore;
95
96 impl ExternalStore for NormalStore {
97 type Id = Hash;
98
99 async fn save_data(
100 &self,
101 _: &[u8],
102 _: &[Self::Id],
103 wh: WithHash<'_, impl Send + Sync + ToOutput>,
104 ) -> object_rainbow::Result<Self::Id> {
105 Ok(wh.data_hash())
106 }
107
108 async fn contains_data(
109 &self,
110 _: &[u8],
111 _: &[Self::Id],
112 _: WithHash<'_, impl Send + Sync + ToOutput>,
113 ) -> object_rainbow::Result<bool> {
114 unimplemented!()
115 }
116
117 async fn contains(&self, _: &Self::Id) -> object_rainbow::Result<bool> {
118 unimplemented!()
119 }
120
121 #[expect(refining_impl_trait)]
122 async fn fetch(&self, _: &Self::Id) -> object_rainbow::Result<Vec<u8>> {
123 unimplemented!()
124 }
125 }
126
127 #[derive(Clone, Copy, PartialEq, Eq)]
128 struct InverseKey;
129
130 impl Key for InverseKey {
131 type Error = Infallible;
132
133 fn encrypt(&self, data: &[u8]) -> Vec<u8> {
134 data.iter().copied().map(|x| !x).collect()
135 }
136
137 fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error> {
138 Ok(data.iter().copied().map(|x| !x).collect())
139 }
140 }
141
142 #[apply(test!)]
143 async fn equivalent_to_normal() -> object_rainbow::Result<()> {
144 let o = ((*b"a"), ((*b"b"), (*b"c").point()).point());
145 let e = encrypt(InverseKey, o.clone()).await?;
146 let f = e.full_hash();
147 let s = EncryptedStore::new(NormalStore, InverseKey);
148 let h = s.store_object(o).await?;
149 assert_eq!(f, h);
150 Ok(())
151 }
152}