1mod dec;
7mod enc;
8mod serde_util;
9
10pub use dec::{decode, decode_const, Error, Result};
11pub use enc::{encode, encode_const, BlockSize, Encoder};
12
13#[cfg(test)]
14mod tests;
15
16pub const TARGET_SPECIFICATION: &str = "1.0.0";
23
24use async_trait::async_trait;
25use blake2::{digest::consts::U32, Blake2b, Digest};
26use chacha20::cipher::{KeyIvInit, StreamCipher};
27use chacha20::ChaCha20;
28use derive_more::{DebugCustom, Deref, DerefMut, Display, From};
29use serde::{Deserialize, Serialize};
30use std::{collections::HashMap, sync::RwLock};
31
32fn display_base32(bytes: &[u8]) -> String {
33 base32::encode(base32::Alphabet::RFC4648 { padding: false }, bytes)
34}
35
36#[cfg(test)]
38fn vardecode_base32(s: &str) -> Result<Vec<u8>> {
39 let buf = base32::decode(base32::Alphabet::RFC4648 { padding: false }, s)
40 .ok_or(Error::InvalidBase32)?;
41 Ok(buf)
42}
43
44fn decode_base32<const BS: usize>(s: &str) -> Result<[u8; BS]> {
45 match base32::decode(base32::Alphabet::RFC4648 { padding: false }, s)
46 .ok_or(Error::InvalidBase32)
47 {
48 Ok(v) if v.len() == BS => Ok(v.try_into().map_err(|_| Error::InvalidBase32)?),
49 Ok(_) => Err(Error::UnexpectedBlockSize),
50 Err(e) => Err(e),
51 }
52}
53
54#[derive(
56 Clone,
57 Copy,
58 PartialEq,
59 Eq,
60 Hash,
61 Deref,
62 PartialOrd,
63 Ord,
64 From,
65 Display,
66 DebugCustom,
67 Serialize,
68 Deserialize,
69)]
70#[display(fmt = "{}", "display_base32(&self.0)")]
71#[debug(fmt = "{}", "self")]
72pub struct BlockReference(pub [u8; 32]);
73
74impl BlockReference {
75 pub fn as_slice(&self) -> &[u8] {
76 &self.0
77 }
78 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
79 bytes
80 .try_into()
81 .map(|inner| Self(inner))
82 .map_err(|_| crate::Error::UnexpectedBlockSize)
83 }
84}
85
86impl TryFrom<&String> for BlockReference {
87 type Error = Error;
88 fn try_from(s: &String) -> Result<BlockReference> {
89 let buf = decode_base32(s.as_str())?;
90 Ok(BlockReference(buf))
91 }
92}
93
94#[derive(
96 Clone,
97 Copy,
98 PartialEq,
99 Eq,
100 Hash,
101 Deref,
102 PartialOrd,
103 Ord,
104 From,
105 Display,
106 DebugCustom,
107 Serialize,
108 Deserialize,
109)]
110#[display(fmt = "{}", "display_base32(&self.0)")]
111#[debug(fmt = "{}", "self")]
112pub struct BlockKey(pub [u8; 32]);
113
114impl BlockKey {
115 pub fn as_slice(&self) -> &[u8] {
116 &self.0
117 }
118
119 pub fn from_bytes(input: &[u8]) -> Result<Self> {
120 input
121 .try_into()
122 .map(|inner| Self(inner))
123 .map_err(|_| crate::Error::UnexpectedKeySize)
124 }
125}
126
127impl TryFrom<&String> for BlockKey {
128 type Error = Error;
129 fn try_from(s: &String) -> Result<BlockKey> {
130 let buf = decode_base32(s.as_str())?;
131 Ok(BlockKey(buf))
132 }
133}
134
135#[doc(hidden)] pub type RKPair = (BlockReference, BlockKey);
137
138#[derive(Clone, Deref, DerefMut, From, Display, DebugCustom, Serialize, Deserialize)]
140#[display(fmt = "{}", "display_base32(&self.0)")]
141#[debug(fmt = "{}", "self")]
142pub struct Block<const BS: usize>(#[serde(with = "serde_util")] [u8; BS]);
143
144impl<const BS: usize> Block<BS> {
145 pub fn as_slice(&self) -> &[u8; BS] {
146 &self.0
147 }
148
149 pub fn copy_from_vec(vec: Vec<u8>) -> Self {
151 let mut buf = [0; BS];
152 buf.copy_from_slice(vec.as_slice());
153 Self(buf)
154 }
155
156 pub fn to_vec(self) -> Vec<u8> {
157 self.0.to_vec()
158 }
159}
160
161impl<const BS: usize> TryFrom<&String> for Block<BS> {
162 type Error = Error;
163 fn try_from(s: &String) -> Result<Block<BS>> {
164 let buf = decode_base32(s.as_str())?;
165 Ok(Block(buf))
166 }
167}
168
169#[async_trait]
170pub trait BlockStorage<const BS: usize> {
171 async fn store(&self, block: &Block<BS>) -> std::io::Result<()>;
172 async fn fetch(&self, reference: &BlockReference) -> std::io::Result<Option<Block<BS>>>;
173}
174
175pub type MemoryStorage = RwLock<HashMap<BlockReference, Vec<u8>>>;
176
177#[async_trait]
178impl<const BS: usize> BlockStorage<BS> for MemoryStorage {
179 async fn store(&self, block: &Block<BS>) -> std::io::Result<()> {
180 self.write()
181 .unwrap()
182 .insert(block.reference(), block.0.to_vec());
183 Ok(())
184 }
185
186 async fn fetch(&self, reference: &BlockReference) -> std::io::Result<Option<Block<BS>>> {
187 self.read()
188 .unwrap()
189 .get(reference)
190 .map(|x| -> std::io::Result<_> {
191 let arr: [u8; BS] = x.clone().try_into().map_err(|_| {
192 std::io::Error::new(std::io::ErrorKind::Other, "Block has unexpected size")
193 })?;
194 Ok(arr.into())
195 })
196 .transpose()
197 }
198}
199
200const fn num_bits<T>() -> usize {
201 std::mem::size_of::<T>() * 8
202}
203
204fn log_2(x: usize) -> u32 {
206 assert!(x > 0);
207 num_bits::<usize>() as u32 - x.leading_zeros() - 1
208}
209
210#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
211pub struct ReadCapability {
212 pub root_reference: BlockReference,
213 pub root_key: BlockKey,
214 pub level: u8,
215 pub block_size: usize,
216}
217
218impl ReadCapability {
219 pub fn from_rk_pair(rk_pair: RKPair, level: u8, block_size: usize) -> ReadCapability {
220 ReadCapability {
221 root_reference: rk_pair.0,
222 root_key: rk_pair.1,
223 level,
224 block_size,
225 }
226 }
227
228 pub fn binary(&self) -> Vec<u8> {
229 let mut out = vec![];
230 out.push(log_2(self.block_size) as u8);
231 out.push(self.level);
232 out.extend_from_slice(&*self.root_reference);
233 out.extend_from_slice(&*self.root_key);
234 out
235 }
236
237 pub fn from_binary(buf: &[u8]) -> Option<ReadCapability> {
238 if buf.len() != 1 + 1 + 32 + 32 {
239 return None;
240 }
241 let block_size = 2usize.pow(buf[0].into());
242 let level = buf[1];
243 let root_reference_bytes: [u8; 32] = buf[2..34].try_into().unwrap();
244 let root_key_bytes: [u8; 32] = buf[34..66].try_into().unwrap();
245 let root_reference = BlockReference::from(root_reference_bytes);
246 let root_key = BlockKey::from(root_key_bytes);
247 Some(Self {
248 block_size,
249 level,
250 root_reference,
251 root_key,
252 })
253 }
254
255 pub fn urn(&self) -> String {
256 format!("urn:erisx2:{}", &display_base32(&self.binary()))
257 }
258}
259
260impl<const BS: usize> Block<BS> {
261 pub fn reference(&self) -> BlockReference {
262 let mut hasher = Blake2b::<U32>::new();
263 Digest::update(&mut hasher, &**self);
264 BlockReference(hasher.finalize().into())
265 }
266
267 pub fn chacha20(&mut self, key: &BlockKey) {
268 let nonce = [0; 12];
270 let mut cipher = ChaCha20::new(&(**key).into(), &nonce.into());
271 cipher.apply_keystream(&mut **self);
272 }
273}