Skip to main content

object_rainbow_encrypted/
lib.rs

1//! See [`Encrypted`], [`encrypt`] and [`encrypt_point`].
2//!
3//! Political/historical note regarding this whole object encryption thing: originally
4//! [`object_rainbow`] (or, rather, its predecessor) was meant for fully open plaintext, but at some
5//! point encryption was added in as proof-of-concept mechanism. The goal since the beginning was to
6//! make encryption an "outside" capability: have core tools powerful enough to allow for such. In
7//! process of making the original Python implementation, I effectively had to invent quite a lot of
8//! things including custom dynamic tracing, since the trickiness of the whole resolution
9//! choreography was quite excessive to track. One of the first things we got to facilitate
10//! encryption was fairly implicit in Python: downcasting [`object_rainbow::Fetch`]es (`Origin`s),
11//! which is now the same thing that powers object stores. Then we had to introduce [`Address`] to
12//! have resolution translation be less messy (before that, it used to be [`Hash`]-only). In this
13//! actual project, main changes were in ways to forward keys. The now-removed first solution was
14//! with dynamically typed extensions, which got replaced with so called "`Extra`"", the system
15//! now resonsible for a lot of advanced functionality we have. Probably the only
16//! encryption-specific concession which we just had to make (I did try doing it differently,
17//! didn't work) was mangle hash. It is a bit of a tax on the project as a whole, so we are looking
18//! for some potentially more local alternatives.
19use std::{
20    ops::{Deref, DerefMut},
21    sync::Arc,
22};
23
24use object_rainbow::{
25    Address, ByteNode, Error, ExtraFor, FailFuture, Fetch, FetchBytes, Hash, ListHashes, Node,
26    Parse, ParseInline, ParseSliceExtra, PointInput, PointVisitor, Resolve, Singular,
27    SingularFetch, Tagged, ToOutput, TopoVec, Topological, Traversible,
28    addressed::ExtractResolve,
29    derive_for_wrapped,
30    fn_fetch::{FnFetch, closure_fetch},
31    length_prefixed::LpVec,
32    map_extra::MappedExtra,
33    tuple_extra::Extra0,
34};
35use object_rainbow_point::{Extras, Point};
36
37pub mod tuple_key;
38
39#[derive_for_wrapped]
40pub trait Key: 'static + Sized + Send + Sync + Clone + PartialEq + Eq {
41    type Error: 'static + Send + Sync + std::error::Error;
42    fn encrypt(&self, data: &[u8]) -> Vec<u8>;
43    fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error>;
44    fn mangle_prefix(&self) -> Vec<u8> {
45        self.encrypt(b"this encrypted constant is followed by an unencrypted inner hash")
46    }
47    fn encrypt_output(&self, object: impl ToOutput) -> Vec<u8> {
48        self.encrypt(&object.vec())
49    }
50}
51
52#[derive(ToOutput, Parse, ParseInline, Clone)]
53struct RawResolve<K> {
54    key: Extras<K>,
55    resolve: Arc<dyn Resolve>,
56    addresses: Arc<LpVec<Address>>,
57}
58
59impl<K> RawResolve<K> {
60    fn translate(&self, address: Address) -> object_rainbow::Result<Address> {
61        self.addresses
62            .get(address.index)
63            .copied()
64            .ok_or(Error::AddressOutOfBounds)
65    }
66}
67
68fn side_parse<K: Key>(
69    key: &K,
70    data: &[u8],
71    resolve: &Arc<dyn Resolve>,
72) -> object_rainbow::Result<(InnerHeader<K>, Vec<u8>)> {
73    let data = key
74        .decrypt(data)
75        .map_err(object_rainbow::Error::consistency)?;
76    <(InnerHeader<K>, Vec<u8>) as ParseSliceExtra<K>>::parse_slice_extra(&data, resolve, key)
77}
78
79impl<K: Key> Resolve for RawResolve<K> {
80    fn resolve<'a>(
81        &'a self,
82        address: Address,
83        _: &'a Arc<dyn Resolve>,
84    ) -> FailFuture<'a, ByteNode> {
85        Box::pin(async move {
86            let address = self.translate(address)?;
87            let (data, resolve) = self.resolve.resolve(address, &self.resolve).await?;
88            let (InnerHeader { resolve, .. }, data) = side_parse(&self.key.0, &data, &resolve)?;
89            let resolve = Arc::new(resolve) as _;
90            Ok((data, resolve))
91        })
92    }
93
94    fn resolve_data(&'_ self, address: Address) -> FailFuture<'_, Vec<u8>> {
95        Box::pin(async move {
96            let address = self.translate(address)?;
97            let (data, resolve) = self.resolve.resolve(address, &self.resolve).await?;
98            let (_, data) = side_parse(&self.key.0, &data, &resolve)?;
99            Ok(data)
100        })
101    }
102
103    fn try_resolve_local(
104        &self,
105        address: Address,
106        _: &Arc<dyn Resolve>,
107    ) -> object_rainbow::Result<Option<ByteNode>> {
108        let address = self.translate(address)?;
109        let Some((data, resolve)) = self.resolve.try_resolve_local(address, &self.resolve)? else {
110            return Ok(None);
111        };
112        let (InnerHeader { resolve, .. }, data) = side_parse(&self.key.0, &data, &resolve)?;
113        let resolve = Arc::new(resolve) as _;
114        Ok(Some((data, resolve)))
115    }
116}
117
118#[derive(Parse, ParseInline)]
119struct InnerHeader<K> {
120    tags: Hash,
121    resolve: RawResolve<K>,
122}
123
124impl<K: Key> InnerHeader<K> {
125    fn with<T: Topological + Tagged>(self, decrypted: T) -> object_rainbow::Result<Inner<K, T>> {
126        if self.tags != T::HASH {
127            return Err(object_rainbow::error_consistency!("tags mismatch"));
128        }
129        let mut topology = TopoVec::new();
130        let mut v = RawVisit {
131            at: 0,
132            resolve: &self.resolve,
133            visitor: &mut topology,
134        };
135        decrypted.traverse(&mut v);
136        v.done()?;
137        let topology = Arc::new(LpVec(topology));
138        let decrypted = Arc::new(decrypted);
139        Ok(Inner {
140            tags: self.tags,
141            key: self.resolve.key,
142            topology,
143            decrypted,
144        })
145    }
146}
147
148#[derive(ToOutput)]
149struct Inner<K, T> {
150    tags: Hash,
151    key: Extras<K>,
152    topology: Arc<LpVec<Arc<dyn Singular>>>,
153    decrypted: Arc<T>,
154}
155
156struct RawVisit<'a, K, V> {
157    at: usize,
158    resolve: &'a RawResolve<K>,
159    visitor: &'a mut V,
160}
161
162impl<'a, K, V> RawVisit<'a, K, V> {
163    fn done(self) -> object_rainbow::Result<()> {
164        if self.at != self.resolve.addresses.len() {
165            Err(Error::AddressOutOfBounds)
166        } else {
167            Ok(())
168        }
169    }
170}
171
172#[derive(Clone)]
173struct RawFetch<K, D> {
174    key: K,
175    resolve: Arc<dyn Resolve>,
176    address: Address,
177    decrypted: D,
178}
179
180impl<K, D> FetchBytes for RawFetch<K, D> {
181    fn fetch_bytes(&'_ self) -> FailFuture<'_, ByteNode> {
182        self.resolve.resolve(self.address, &self.resolve)
183    }
184
185    fn fetch_data(&'_ self) -> FailFuture<'_, Vec<u8>> {
186        self.resolve.resolve_data(self.address)
187    }
188
189    fn fetch_bytes_local(&self) -> object_rainbow::Result<Option<ByteNode>> {
190        self.resolve.try_resolve_local(self.address, &self.resolve)
191    }
192}
193
194impl<K: Key, D: Fetch<T: Topological + Tagged>> Fetch for RawFetch<K, D> {
195    type T = Encrypted<K, D::T>;
196
197    fn fetch(&'_ self) -> FailFuture<'_, Self::T> {
198        Box::pin(async move {
199            let (encrypted, resolve) = self.resolve.resolve(self.address, &self.resolve).await?;
200            let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
201            let decrypted = self.decrypted.fetch().await?;
202            let inner = header.with(decrypted)?;
203            Ok(Encrypted { inner })
204        })
205    }
206
207    fn try_fetch_local(&self) -> object_rainbow::Result<Option<Node<Self::T>>> {
208        let Some((encrypted, resolve)) = self
209            .resolve
210            .try_resolve_local(self.address, &self.resolve)?
211        else {
212            return Ok(None);
213        };
214        let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
215        let Some((decrypted, _)) = self.decrypted.try_fetch_local()? else {
216            return Ok(None);
217        };
218        let inner = header.with(decrypted)?;
219        Ok(Some((Encrypted { inner }, resolve)))
220    }
221}
222
223impl<K: Send + Sync, D: Send + Sync> Singular for RawFetch<K, D> {
224    fn hash(&self) -> Hash {
225        self.address.hash
226    }
227}
228
229impl<'a, K: Key, V: PointVisitor> PointVisitor for RawVisit<'a, K, V> {
230    fn visit(&mut self, point: &(impl 'static + SingularFetch<T: Traversible> + Clone)) {
231        let at = self.at;
232        self.at += 1;
233        if let Some(address) = self.resolve.addresses.get(at).copied() {
234            let key = self.resolve.key.0.clone();
235            let resolve = self.resolve.resolve.clone();
236            let decrypted = point.clone();
237            self.visitor.visit(&RawFetch {
238                key,
239                resolve,
240                address,
241                decrypted,
242            });
243        }
244    }
245}
246
247impl<
248    K: Key,
249    T: Topological + Tagged,
250    Extra: 'static + Send + Sync + Clone + ExtraFor<T>,
251    I: PointInput<Extra = (K, Extra)>,
252> Parse<I> for Inner<K, T>
253{
254    fn parse(mut input: I) -> object_rainbow::Result<Self> {
255        let header = input
256            .parse_inline::<MappedExtra<InnerHeader<K>, Extra0>>()?
257            .1;
258        let extra = input.extra().1.clone();
259        let decrypted = extra.parse(
260            &input.parse_all()?,
261            &(Arc::new(header.resolve.clone()) as _),
262        )?;
263        if decrypted.point_count() != header.resolve.addresses.len() {
264            return Err(object_rainbow::error_consistency!(
265                "too many addresses in the header",
266            ));
267        }
268        header.with(decrypted)
269    }
270}
271
272impl<K: Clone, T> Clone for Inner<K, T> {
273    fn clone(&self) -> Self {
274        Self {
275            tags: self.tags,
276            key: self.key.clone(),
277            topology: self.topology.clone(),
278            decrypted: self.decrypted.clone(),
279        }
280    }
281}
282
283#[derive(Clone)]
284struct InnerFetch<K, D> {
285    key: K,
286    encrypted: Arc<dyn Singular>,
287    decrypted: D,
288}
289
290impl<K, D> FetchBytes for InnerFetch<K, D> {
291    fn fetch_bytes(&'_ self) -> FailFuture<'_, ByteNode> {
292        self.encrypted.fetch_bytes()
293    }
294
295    fn fetch_data(&'_ self) -> FailFuture<'_, Vec<u8>> {
296        self.encrypted.fetch_data()
297    }
298
299    fn fetch_bytes_local(&self) -> object_rainbow::Result<Option<ByteNode>> {
300        self.encrypted.fetch_bytes_local()
301    }
302
303    fn fetch_data_local(&self) -> Option<Vec<u8>> {
304        self.encrypted.fetch_data_local()
305    }
306}
307
308impl<K: Key, D: Fetch<T: Topological + Tagged>> Fetch for InnerFetch<K, D> {
309    type T = Encrypted<K, D::T>;
310
311    fn fetch(&'_ self) -> FailFuture<'_, Self::T> {
312        Box::pin(async move {
313            let (encrypted, resolve) = self.encrypted.fetch_bytes().await?;
314            let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
315            let decrypted = self.decrypted.fetch().await?;
316            let inner = header.with(decrypted)?;
317            Ok(Encrypted { inner })
318        })
319    }
320
321    fn try_fetch_local(&self) -> object_rainbow::Result<Option<Node<Self::T>>> {
322        let Some((encrypted, resolve)) = self.encrypted.fetch_bytes_local()? else {
323            return Ok(None);
324        };
325        let (header, _) = side_parse(&self.key, &encrypted, &resolve)?;
326        let Some((decrypted, _)) = self.decrypted.try_fetch_local()? else {
327            return Ok(None);
328        };
329        let inner = header.with(decrypted)?;
330        Ok(Some((Encrypted { inner }, resolve)))
331    }
332}
333
334impl<K: Send + Sync, D: Send + Sync> Singular for InnerFetch<K, D> {
335    fn hash(&self) -> Hash {
336        self.encrypted.hash()
337    }
338}
339
340struct IterateResolution<'a, 'r, K, V> {
341    key: &'a K,
342    topology: &'r mut std::slice::Iter<'a, Arc<dyn Singular>>,
343    visitor: &'a mut V,
344}
345
346impl<'a, K: Key, V: PointVisitor> PointVisitor for IterateResolution<'a, '_, K, V> {
347    fn visit(&mut self, decrypted: &(impl 'static + SingularFetch<T: Traversible> + Clone)) {
348        let decrypted = decrypted.clone();
349        let encrypted = self.topology.next().expect("length mismatch").clone();
350        let point = Point::from_singular(InnerFetch {
351            key: self.key.clone(),
352            decrypted,
353            encrypted,
354        });
355        self.visitor.visit(&point);
356    }
357}
358
359impl<K, T> ListHashes for Inner<K, T> {
360    fn list_hashes(&self, f: &mut impl FnMut(Hash)) {
361        self.topology.list_hashes(f);
362    }
363
364    fn topology_hash(&self) -> Hash {
365        self.topology.0.data_hash()
366    }
367
368    fn point_count(&self) -> usize {
369        self.topology.len()
370    }
371}
372
373impl<K: Key, T: Topological> Topological for Inner<K, T> {
374    fn traverse(&self, visitor: &mut impl PointVisitor) {
375        let topology = &mut self.topology.iter();
376        self.decrypted.traverse(&mut IterateResolution {
377            key: &self.key.0,
378            topology,
379            visitor,
380        });
381        assert!(topology.next().is_none());
382    }
383
384    fn topology(&self) -> TopoVec {
385        self.topology.0.clone()
386    }
387}
388
389pub struct Encrypted<K, T> {
390    inner: Inner<K, T>,
391}
392
393impl<K, T: Clone> Encrypted<K, T> {
394    pub fn into_inner(self) -> T {
395        Arc::unwrap_or_clone(self.inner.decrypted)
396    }
397}
398
399impl<K, T> Deref for Encrypted<K, T> {
400    type Target = T;
401
402    fn deref(&self) -> &Self::Target {
403        self.inner.decrypted.as_ref()
404    }
405}
406
407impl<K: Clone, T> Clone for Encrypted<K, T> {
408    fn clone(&self) -> Self {
409        Self {
410            inner: self.inner.clone(),
411        }
412    }
413}
414
415impl<K, T> ListHashes for Encrypted<K, T> {
416    fn list_hashes(&self, f: &mut impl FnMut(Hash)) {
417        self.inner.list_hashes(f);
418    }
419
420    fn topology_hash(&self) -> Hash {
421        self.inner.topology_hash()
422    }
423
424    fn point_count(&self) -> usize {
425        self.inner.point_count()
426    }
427}
428
429impl<K: Key, T: Topological> Topological for Encrypted<K, T> {
430    fn traverse(&self, visitor: &mut impl PointVisitor) {
431        self.inner.traverse(visitor);
432    }
433}
434
435impl<K: Key, T: ToOutput> ToOutput for Encrypted<K, T> {
436    fn to_output(&self, output: &mut impl object_rainbow::Output) {
437        if output.is_mangling() {
438            output.write(&*self.inner.key.mangle_prefix().data_hash());
439            output.write(&*self.inner.decrypted.data_hash());
440        }
441        if output.is_real() {
442            output.write(&self.inner.key.encrypt_output(&self.inner));
443        }
444    }
445}
446
447trait EncryptedExtra<K>: 'static + Send + Sync + Clone {
448    type Extra: 'static + Send + Sync + Clone;
449    fn parts(&self) -> (K, Self::Extra);
450}
451
452impl<K: 'static + Send + Sync + Clone, Extra: 'static + Send + Sync + Clone> EncryptedExtra<K>
453    for (K, Extra)
454{
455    type Extra = Extra;
456
457    fn parts(&self) -> (K, Self::Extra) {
458        self.clone()
459    }
460}
461
462impl<K: 'static + Send + Sync + Clone> EncryptedExtra<K> for K {
463    type Extra = ();
464
465    fn parts(&self) -> (K, Self::Extra) {
466        (self.clone(), ())
467    }
468}
469
470impl<
471    K: Key,
472    T: Topological + Tagged,
473    Extra: 'static + Send + Sync + Clone + ExtraFor<T>,
474    I: PointInput<Extra: EncryptedExtra<K, Extra = Extra>>,
475> Parse<I> for Encrypted<K, T>
476{
477    fn parse(input: I) -> object_rainbow::Result<Self> {
478        let with_key = input.extra().parts();
479        let resolve = input.resolve().clone();
480        let source = with_key
481            .0
482            .decrypt(&input.parse_all()?)
483            .map_err(object_rainbow::Error::consistency)?;
484        let inner = Inner::<K, T>::parse_slice_extra(&source, &resolve, &with_key)?;
485        Ok(Self { inner })
486    }
487}
488
489impl<K, T> Tagged for Encrypted<K, T> {}
490
491type Extracted =
492    Vec<std::pin::Pin<Box<dyn Future<Output = Result<Arc<dyn Singular>, Error>> + Send + 'static>>>;
493
494struct ExtractResolution<'a, K> {
495    extracted: &'a mut Extracted,
496    key: &'a K,
497}
498
499impl<K: Key> PointVisitor for ExtractResolution<'_, K> {
500    fn visit(&mut self, decrypted: &(impl 'static + SingularFetch<T: Traversible> + Clone)) {
501        let decrypted = decrypted.clone();
502        let key = self.key.clone();
503        self.extracted.push(Box::pin(async move {
504            Ok(Arc::new(encrypt_point(key, decrypted).await?) as _)
505        }));
506    }
507}
508
509pub async fn encrypt_point<K: Key, T: Traversible>(
510    key: K,
511    decrypted: impl 'static + SingularFetch<T = T>,
512) -> object_rainbow::Result<Point<Encrypted<K, T>>> {
513    if let Some((address, resolve)) = decrypted.extract_resolve::<RawResolve<K>>()
514        && resolve.key.0 == key
515    {
516        let address = resolve.translate(*address)?;
517        let point = Point::from_singular(RawFetch {
518            key,
519            resolve: resolve.resolve.clone(),
520            address,
521            decrypted,
522        });
523        return Ok(point);
524    };
525    let encrypted = encrypt(key.clone(), decrypted.fetch().await?).await?;
526    let topology = encrypted.inner.topology.clone();
527    let point = Point::from_alternate_source(
528        &encrypted,
529        FnFetch::new(closure_fetch(
530            (key, decrypted, topology),
531            async |(key, decrypted, topology)| {
532                let decrypted = decrypted.fetch().await?;
533                let topology = topology.clone();
534                let key = key.clone();
535                Ok(Encrypted::from_topology(key, topology, decrypted))
536            },
537        )),
538    );
539    Ok(point)
540}
541
542pub async fn encrypt<K: Key, T: Traversible>(
543    key: K,
544    decrypted: T,
545) -> object_rainbow::Result<Encrypted<K, T>> {
546    let mut futures = Vec::with_capacity(decrypted.point_count());
547    decrypted.traverse(&mut ExtractResolution {
548        extracted: &mut futures,
549        key: &key,
550    });
551    let topology = futures_util::future::try_join_all(futures).await?;
552    let topology = Arc::new(LpVec(topology));
553    Ok(Encrypted::from_topology(key, topology, decrypted))
554}
555
556impl<K: Key, T: Traversible> Encrypted<K, T> {
557    fn from_topology(key: K, topology: Arc<LpVec<Arc<dyn Singular>>>, decrypted: T) -> Self {
558        let decrypted = Arc::new(decrypted);
559        let inner = Inner {
560            tags: T::HASH,
561            key: Extras(key),
562            topology,
563            decrypted,
564        };
565        Self { inner }
566    }
567}
568
569impl<K: Key, T: Traversible + Clone> Encrypted<K, T> {
570    pub fn as_mut(&mut self) -> EncryptedMut<'_, K, T> {
571        let object = self.inner.decrypted.as_ref().clone();
572        EncryptedMut {
573            encrypted: self,
574            object,
575        }
576    }
577}
578
579pub struct EncryptedMut<'a, K, T> {
580    encrypted: &'a mut Encrypted<K, T>,
581    object: T,
582}
583
584impl<K, T> Deref for EncryptedMut<'_, K, T> {
585    type Target = T;
586
587    fn deref(&self) -> &Self::Target {
588        &self.object
589    }
590}
591
592impl<K, T> DerefMut for EncryptedMut<'_, K, T> {
593    fn deref_mut(&mut self) -> &mut Self::Target {
594        &mut self.object
595    }
596}
597
598impl<'a, K: Key, T: Traversible> EncryptedMut<'a, K, T> {
599    pub async fn save(self) -> object_rainbow::Result<()> {
600        *self.encrypted = encrypt(self.encrypted.inner.key.0.clone(), self.object).await?;
601        Ok(())
602    }
603}