async_eris/
enc.rs

1// SPDX-FileCopyrightText: 2022 Yureka Lilian <yuka@yuka.dev>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later WITH LicenseRef-AppStore
4
5use crate::{Block, BlockKey, BlockStorage, RKPair, ReadCapability};
6use blake2::{
7    digest::consts::U32, digest::FixedOutput, digest::KeyInit, digest::Update, Blake2bMac,
8};
9use futures_lite::io::{AsyncRead, AsyncReadExt};
10
11impl<const BS: usize> Block<BS> {
12    fn encrypt(&mut self, convergence_secret: &[u8; 32]) -> RKPair {
13        let key = self.derive_key(convergence_secret);
14        self.chacha20(&key);
15        let reference = self.reference();
16        (reference, key)
17    }
18
19    fn derive_key(&self, convergence_secret: &[u8; 32]) -> BlockKey {
20        let mut hasher = Blake2bMac::<U32>::new_from_slice(convergence_secret).unwrap();
21        Update::update(&mut hasher, &**self);
22        BlockKey(hasher.finalize_fixed().into())
23    }
24}
25
26pub struct Encoder<'a, S: BlockStorage<BS>, const BS: usize> {
27    pub convergence_secret: [u8; 32],
28    pub block_storage: &'a S,
29}
30
31/// Supported block sizes by this implementation
32#[derive(thiserror::Error, Clone, Copy, Debug)]
33pub enum BlockSize {
34    #[error("1kB")]
35    _1K,
36    #[error("32kB")]
37    _32K,
38}
39
40/// Encode an async read stream into a set of blocks
41///
42/// Blocks are asynchronously streamed into the `block_storage` (which
43/// may simply be in-memory, but could be on-disk for larger payloads).
44///
45/// This function returns a `ReadCapability`, which acts as a manifest
46/// for the generated blocks.
47pub async fn encode<S: BlockStorage<1024> + BlockStorage<32768>, R: AsyncRead + Unpin>(
48    content: &mut R,
49    convergence_secret: &[u8; 32],
50    block_size: BlockSize,
51    block_storage: &S,
52) -> std::io::Result<ReadCapability> {
53    match block_size {
54        BlockSize::_1K => {
55            encode_const::<_, _, 1024>(content, convergence_secret, block_storage).await
56        }
57        BlockSize::_32K => {
58            encode_const::<_, _, 32768>(content, convergence_secret, block_storage).await
59        }
60    }
61}
62
63pub async fn encode_const<S: BlockStorage<BS>, R: AsyncRead + Unpin, const BS: usize>(
64    content: &mut R,
65    convergence_secret: &[u8; 32],
66    block_storage: &S,
67) -> std::io::Result<ReadCapability> {
68    let mut encoder = Encoder::<S, BS> {
69        convergence_secret: convergence_secret.clone(),
70        block_storage,
71    };
72    encoder.encode(content).await
73}
74
75impl<'a, S: BlockStorage<BS>, const BS: usize> Encoder<'a, S, BS> {
76    pub async fn encode<R: AsyncRead + Unpin>(
77        &mut self,
78        content: &mut R,
79    ) -> std::io::Result<ReadCapability> {
80        let mut level = 0;
81        let mut rk_pairs = self.split_content(content).await?;
82
83        while rk_pairs.len() > 1 {
84            let new_rk_pairs = self.collect_rk_pairs(rk_pairs).await?;
85            rk_pairs = new_rk_pairs;
86            level += 1;
87        }
88
89        let root = rk_pairs.remove(0);
90        Ok(ReadCapability::from_rk_pair(root, level, BS))
91    }
92
93    async fn split_content<R: AsyncRead + Unpin>(
94        &mut self,
95        content: &mut R,
96    ) -> std::io::Result<Vec<RKPair>> {
97        let mut rk_pairs = vec![];
98        let mut buf = Block([0u8; BS]);
99        let mut pos;
100        loop {
101            pos = 0;
102            while pos < BS {
103                match content.read(&mut buf[pos..]).await? {
104                    0 => break,
105                    n => {
106                        pos += n;
107                    }
108                };
109            }
110            if pos != BS {
111                buf[pos..].fill(0);
112                buf[pos] = 0x80;
113            }
114
115            let rk_pair = buf.encrypt(&self.convergence_secret);
116            self.block_storage.store(&buf).await?;
117            rk_pairs.push(rk_pair);
118            if pos != BS {
119                break;
120            };
121        }
122
123        Ok(rk_pairs)
124    }
125
126    async fn collect_rk_pairs(
127        &mut self,
128        input_rk_pairs: Vec<RKPair>,
129    ) -> std::io::Result<Vec<RKPair>> {
130        let arity = BS / 64;
131
132        let mut output_rk_pairs = vec![];
133
134        for rk_pairs_for_node in input_rk_pairs.chunks(arity) {
135            let mut node = Block([0u8; BS]);
136            for (x, pair) in rk_pairs_for_node.iter().enumerate() {
137                node[64 * x..64 * x + 32].copy_from_slice(&pair.0 .0);
138                node[64 * x + 32..64 * x + 64].copy_from_slice(&pair.1 .0);
139            }
140
141            let rk_pair = node.encrypt(&self.convergence_secret);
142
143            self.block_storage.store(&node).await?;
144            output_rk_pairs.push(rk_pair);
145        }
146
147        Ok(output_rk_pairs)
148    }
149}