ConvergentEncryption

Struct ConvergentEncryption 

Source
pub struct ConvergentEncryption;
Expand description

Convergent encryption using AES-256-GCM with Blake3 key derivation and Brotli compression

This implementation provides convergent encryption where the encryption key is derived from the content itself using Blake3. This enables:

  • Deterministic encryption: Same content always produces the same ciphertext
  • Content-based deduplication: Identical files can be identified by their key
  • No key management: No need to store or manage encryption keys separately
  • Integrity verification: Can verify file integrity by re-deriving the key
  • Optional compression: Brotli compression reduces storage requirements

§Security Model

  • The 32-byte Blake3 hash serves as both the encryption key and nonce (first 12 bytes)
  • AES-256-GCM provides authenticated encryption with integrity protection
  • Compression is applied before encryption to maximize storage efficiency
  • The same content will always produce the same ciphertext, enabling deduplication

§Limitations

  • Identical content detection: Adversaries can determine when identical files are stored
  • No forward secrecy: If the content is known, the encryption can be broken

This approach is ideal for scenarios where you control the content and want to benefit from deduplication and integrity verification.

Implementations§

Source§

impl ConvergentEncryption

Source

pub(crate) fn derive_key(content: &[u8]) -> ConvergentEncryptionKey

Derive encryption key from source content using Blake3

This function calculates a 32-byte encryption key from the content using Blake3. The same content will always produce the same key, enabling convergent encryption.

The derived key is used as both the encryption key and nonce for AES-256-GCM.

§Arguments
  • content - The source content to derive the key from
§Returns

A 32-byte encryption key derived from the content

Source

pub(crate) fn compress( content: &[u8], config: &CompressionConfig, ) -> Result<(Vec<u8>, bool), ConvergentEncryptionError>

Compress content using Brotli if beneficial

Attempts to compress the content using Brotli. Only applies compression if:

  • Compression is enabled in the config
  • Content size is above the minimum threshold
  • Compressed size is smaller than the original
§Arguments
  • content - The content to potentially compress
  • config - Compression configuration settings
§Returns

A tuple containing the data to encrypt (compressed or original) and a flag indicating whether compression was applied.

Source

pub(crate) fn decompress( content: &[u8], ) -> Result<Vec<u8>, ConvergentEncryptionError>

Decompress content using Brotli

Attempts to decompress the content using Brotli. This function assumes the content was compressed and will return an error if decompression fails.

§Arguments
  • content - The compressed content to decompress
§Returns

The decompressed content

Source

pub fn encrypt_with_compression_config( plaintext: &[u8], config: CompressionConfig, ) -> Result<(Vec<u8>, ConvergentEncryptionInfo), ConvergentEncryptionError>

Encrypt plaintext using convergent encryption with custom compression settings

This function performs the complete encryption process:

  1. Derives the encryption key from the content using Blake3
  2. Compresses the content if beneficial (based on config)
  3. Encrypts the data using AES-256-GCM with the derived key
  4. Returns both the ciphertext and metadata for decryption

The same plaintext will always produce the same ciphertext, enabling convergent encryption and deduplication.

§Arguments
  • plaintext - The content to encrypt
  • config - Compression configuration settings
§Returns

A tuple containing the encrypted ciphertext and metadata needed for decryption

§Example
use zoe_encrypted_storage::{ConvergentEncryption, CompressionConfig};

let content = b"Hello, world!";

// Encrypt with custom compression
let config = CompressionConfig {
    enabled: true,
    quality: 8,
    min_size: 128,
};
let (encrypted, info) = ConvergentEncryption::encrypt_with_compression_config(content, config).unwrap();
Source

pub fn decrypt( ciphertext: &[u8], config: &ConvergentEncryptionInfo, ) -> Result<Vec<u8>, ConvergentEncryptionError>

Decrypt ciphertext using the provided metadata with automatic decompression

This function performs the complete decryption process:

  1. Decrypts the ciphertext using AES-256-GCM
  2. Decompresses the data if it was compressed during encryption
  3. Returns the original plaintext
§Arguments
  • ciphertext - The encrypted data to decrypt
  • config - Metadata containing the key and compression information
§Returns

The original plaintext content

§Example
use zoe_encrypted_storage::ConvergentEncryption;

let content = b"Hello, world!";
let (encrypted, info) = ConvergentEncryption::encrypt(content).unwrap();
let decrypted = ConvergentEncryption::decrypt(&encrypted, &info).unwrap();
assert_eq!(content, decrypted.as_slice());
Source

pub fn encrypt( content: &[u8], ) -> Result<(Vec<u8>, ConvergentEncryptionInfo), ConvergentEncryptionError>

Convenience function: encrypt content with default compression settings

This function combines key derivation, compression, and encryption in one step using the default compression configuration. It’s the simplest way to encrypt content with convergent encryption.

§Arguments
  • content - The content to encrypt
§Returns

A tuple containing the encrypted ciphertext and metadata needed for decryption

§Example
use zoe_encrypted_storage::ConvergentEncryption;

let content = b"Hello, world!";
let (encrypted, info) = ConvergentEncryption::encrypt(content).unwrap();
let decrypted = ConvergentEncryption::decrypt(&encrypted, &info).unwrap();
assert_eq!(content, decrypted.as_slice());

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.