cipherstash-client 0.34.1-alpha.1

The official CipherStash SDK
Documentation
use crate::zerokms::IndexKey;
use zeroize::{Zeroize, ZeroizeOnDrop};

use super::{path_values::PathSegment, ste_vec::TokenizedSelector};

pub(crate) trait PrefixMac {
    fn finalize_reset<const N: usize>(&mut self) -> [u8; N];
}

pub(crate) trait UpdatePrefixMac<T> {
    fn update(&mut self, value: T);
}

///
/// Note: this appears to be unused
///
impl<'p, M> UpdatePrefixMac<PathSegment<'p>> for M
where
    for<'s> M: PrefixMac + UpdatePrefixMac<&'s str>,
{
    fn update(&mut self, value: PathSegment<'p>) {
        match value {
            PathSegment::Root => self.update("$"),
            PathSegment::ArrayWildcardItem => self.update("[*]"),
            PathSegment::ArrayItem => self.update("[@]"),
            PathSegment::ArrayPositionItem(i) => self.update(&format!("{i}")),
            PathSegment::ObjectItem(key) => self.update(&format!(".{key}")),
        }
    }
}

impl<const N: usize, M> UpdatePrefixMac<TokenizedSelector<N>> for M
where
    M: PrefixMac + UpdatePrefixMac<[u8; N]>,
{
    fn update(&mut self, value: TokenizedSelector<N>) {
        self.update(value.as_bytes());
    }
}

#[derive(Zeroize, ZeroizeOnDrop)]
pub(super) struct Blake3PrefixMac {
    prefix: Vec<u8>,
    hasher: blake3::Hasher,
}

impl Blake3PrefixMac {
    pub fn new(key: &IndexKey, prefix: Vec<u8>) -> Self {
        let mut hasher = blake3::Hasher::new_keyed(key.key());
        hasher.update(&prefix);

        Self { prefix, hasher }
    }

    fn reset(&mut self) {
        self.hasher.reset();
        self.hasher.update(&self.prefix);
    }
}

impl PrefixMac for Blake3PrefixMac {
    fn finalize_reset<const N: usize>(&mut self) -> [u8; N] {
        let mut output = [0; N];
        self.hasher.finalize_xof().fill(&mut output);
        self.reset();
        output
    }
}

impl UpdatePrefixMac<String> for Blake3PrefixMac {
    fn update(&mut self, mut value: String) {
        self.hasher.update(value.as_bytes());
        value.zeroize();
    }
}

impl UpdatePrefixMac<&str> for Blake3PrefixMac {
    fn update(&mut self, value: &str) {
        self.hasher.update(value.as_bytes());
    }
}

impl UpdatePrefixMac<[u8; 16]> for Blake3PrefixMac {
    fn update(&mut self, mut value: [u8; 16]) {
        self.hasher.update(&value);
        value.zeroize();
    }
}

#[cfg(test)]
mod test {
    // TODO: test that info gets used properly after reset
    // TODO: Check that 2 different indexers with different prefixes produce different results with the same key
    // TODO: Check that 2 different indexers with the same prefix produce different results with different keys
}