Every value in my little embedded key-value store gets encrypted, then
its ciphertext gets encoded as a string of A/C/G/T characters before it
ever touches the filesystem. Open the file in a text editor and you'll
see actual DNA-looking text - not because it's a gimmick, but because
that's genuinely the storage format.
This is mdc-lite
, a ~348KB embeddable encrypted key-value store I
built in Rust for places a server can't reach - a watch face, a phone
app, a background service. It's part of a larger repo, ModelDB,
that also includes MDC, a Python conversational data engine (query AI
models, databases, images, and documents in plain English, no SQL) with
its own DNA-inspired archival storage tier.
Every put()
call does this, in order:
[key_len][key_bytes][value_bytes]
into one plaintext buffer.[nonce][ciphertext][tag]
blob: 2 bits per
base, 00→A 01→C 10→G 11→T
. Every byte maps to exactly 4 bases, so there's no padding ambiguity on decode.Filenames are keyed BLAKE3 hashes of the logical key, not the key name
itself, so a directory listing alone leaks nothing - no key names, no
values, no way to tell how many distinct keys exist versus how many
files are on disk.
rust
pub fn put(&self, key: &str, value: &[u8]) -> Result<(), LiteStoreError> {
let mut plaintext = Vec::new();
plaintext.extend_from_slice(&(key.len() as u16).to_le_bytes());
plaintext.extend_from_slice(key.as_bytes());
plaintext.extend_from_slice(value);
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
let ciphertext = self.cipher().encrypt(&nonce, plaintext.as_ref())?;
let mut record = nonce.to_vec();
record.extend_from_slice(&ciphertext);
let acgt_text = dna::encode(&record); // <- the actual bytes on disk
fs::write(tmp_path, &acgt_text)?;
fs::rename(tmp_path, final_path)?;
Ok(())
}