cipherstash-client 0.41.1

The official CipherStash SDK
Documentation
//! Mode-specific construction of leaf [`EncryptedSteVecTerm`] values.
//!
//! [`PrefixMac`] picks a [`TermBuilder`] via its associated type, so the leaf
//! shape (`Compat` vs. `Standard`) is selected at type-level by the MAC choice
//! rather than threaded through a runtime mode flag.

use super::{
    mac_term::{MacBuild, MacTerm},
    ste_plaintext_term::OrderableTerm,
};
use crate::encryption::{
    json_indexer::{
        prefix_mac::{PrefixMac, UpdatePrefixMac},
        ste_vec::encrypted_term::{
            EncryptedSteVecTerm, EncryptedSteVecTermCompat, EncryptedSteVecTermStandard,
        },
    },
    EncryptionError, TokenizedSelector,
};
use zerokms_protocol::cipherstash_config::column::SteVecMode;

pub(crate) trait TermBuilder {
    fn mac_term<M, const N: usize>(
        macca: &mut M,
        selector: TokenizedSelector<N>,
        term: MacTerm,
    ) -> EncryptedSteVecTerm
    where
        M: PrefixMac + UpdatePrefixMac<MacTerm> + UpdatePrefixMac<TokenizedSelector<N>>;

    fn orderable_term<M>(
        term: OrderableTerm,
        macca: &mut M,
    ) -> Result<EncryptedSteVecTerm, EncryptionError>
    where
        M: PrefixMac + UpdatePrefixMac<&'static str>;
}

/// Continuation invoked with the [`TermBuilder`] selected for a [`SteVecMode`].
///
/// [`dispatch_mode`] is the single place a runtime [`SteVecMode`] is turned into
/// a compile-time [`TermBuilder`]. Every mode-dependent construction path routes
/// through it, so the mode->builder mapping lives in exactly one place; the
/// builder->variant mapping is fixed by each builder's own impl (a
/// [`CompatTermBuilder`] can only produce `EncryptedSteVecTerm::Compat` values,
/// a [`StandardTermBuilder`] only `::Standard`). A column therefore cannot emit
/// the wrong wire key for its mode.
pub(crate) trait WithTermBuilder {
    type Output;
    fn call<TB: TermBuilder>(self) -> Self::Output;
}

pub(crate) fn dispatch_mode<W: WithTermBuilder>(mode: SteVecMode, with: W) -> W::Output {
    match mode {
        SteVecMode::Compat => with.call::<CompatTermBuilder>(),
        SteVecMode::Standard => with.call::<StandardTermBuilder>(),
    }
}

pub(crate) struct CompatTermBuilder;

impl TermBuilder for CompatTermBuilder {
    fn mac_term<M, const N: usize>(
        macca: &mut M,
        selector: TokenizedSelector<N>,
        term: MacTerm,
    ) -> EncryptedSteVecTerm
    where
        M: PrefixMac + UpdatePrefixMac<MacTerm> + UpdatePrefixMac<TokenizedSelector<N>>,
    {
        let mac = MacBuild::from((selector, term)).build(macca);
        EncryptedSteVecTerm::Compat(EncryptedSteVecTermCompat::Mac(mac))
    }

    fn orderable_term<M>(
        term: OrderableTerm,
        macca: &mut M,
    ) -> Result<EncryptedSteVecTerm, EncryptionError>
    where
        M: PrefixMac + UpdatePrefixMac<&'static str>,
    {
        term.build_compat(macca).map(EncryptedSteVecTerm::Compat)
    }
}

pub(crate) struct StandardTermBuilder;

impl TermBuilder for StandardTermBuilder {
    fn mac_term<M, const N: usize>(
        macca: &mut M,
        selector: TokenizedSelector<N>,
        term: MacTerm,
    ) -> EncryptedSteVecTerm
    where
        M: PrefixMac + UpdatePrefixMac<MacTerm> + UpdatePrefixMac<TokenizedSelector<N>>,
    {
        let mac = MacBuild::from((selector, term)).build(macca);
        EncryptedSteVecTerm::Standard(EncryptedSteVecTermStandard::Mac(mac))
    }

    fn orderable_term<M>(
        term: OrderableTerm,
        macca: &mut M,
    ) -> Result<EncryptedSteVecTerm, EncryptionError>
    where
        M: PrefixMac + UpdatePrefixMac<&'static str>,
    {
        term.build_standard(macca)
            .map(EncryptedSteVecTerm::Standard)
    }
}