evidence 0.1.0

Type-level tags for cryptographic primitives
Documentation
//! ChaCha20-Poly1305 encryption implementation.

use alloc::vec::Vec;

use super::EncryptionPrimitive;
use chacha20poly1305::aead::{Aead, AeadCore, KeyInit, OsRng};
use hybrid_array::{Array, typenum::U12};

/// ChaCha20-Poly1305 AEAD primitive (256-bit key, 96-bit nonce).
#[derive(Debug, Clone, Copy)]
pub enum ChaCha20Poly1305 {}

#[allow(clippy::expect_used)] // AEAD encrypt is infallible; nonce size is type-level guaranteed
impl EncryptionPrimitive for ChaCha20Poly1305 {
    type Key = chacha20poly1305::Key;
    type NonceSize = U12;
    type Error = chacha20poly1305::Error;

    fn encrypt(key: &Self::Key, plaintext: &[u8]) -> (Vec<u8>, Array<u8, Self::NonceSize>) {
        let cipher = chacha20poly1305::ChaCha20Poly1305::new(key);
        let nonce = chacha20poly1305::ChaCha20Poly1305::generate_nonce(&mut OsRng);
        let ciphertext = cipher
            .encrypt(&nonce, plaintext)
            .expect("encryption should not fail");

        let nonce_array = Array::try_from(nonce.as_slice()).expect("nonce size matches NonceSize");
        (ciphertext, nonce_array)
    }

    fn encrypt_with_nonce(
        key: &Self::Key,
        nonce: &Array<u8, Self::NonceSize>,
        plaintext: &[u8],
    ) -> Vec<u8> {
        let cipher = chacha20poly1305::ChaCha20Poly1305::new(key);
        let nonce = chacha20poly1305::Nonce::from_slice(nonce.as_slice());
        cipher
            .encrypt(nonce, plaintext)
            .expect("encryption should not fail")
    }

    fn decrypt(
        key: &Self::Key,
        nonce: &Array<u8, Self::NonceSize>,
        ciphertext: &[u8],
    ) -> Result<Vec<u8>, Self::Error> {
        let cipher = chacha20poly1305::ChaCha20Poly1305::new(key);
        let nonce = chacha20poly1305::Nonce::from_slice(nonce.as_slice());
        cipher.decrypt(nonce, ciphertext)
    }
}