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