Skip to content

Commit

Permalink
fix: add Findex tests and correct bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
tbrezot committed Feb 15, 2024
1 parent b5cdc56 commit 546f709
Show file tree
Hide file tree
Showing 7 changed files with 419 additions and 106 deletions.
8 changes: 4 additions & 4 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ pub mod tests {
let db = &mut *self.lock().expect("couldn't lock the table");
let mut res = Edx::default();
for (k, v) in items {
if db.contains_key(&k) {
res.insert(k, v);
if let Some(current_value) = db.get(&k) {
res.insert(k, current_value.clone());
} else {
db.insert(k, v);
}
Expand Down Expand Up @@ -270,7 +270,7 @@ pub mod tests {
/// Tries inserting `N_WORKERS` data using random tokens. Then verifies the
/// inserted, dumped and fetched DX are identical.
#[test]
fn test_insert_then_dump_and_fetch() {
fn insert_then_dump_and_fetch() {
let mut rng = CsRng::from_entropy();
let db = InMemoryDb::default();
let inserted_dx = (0..N_WORKERS)
Expand Down Expand Up @@ -299,7 +299,7 @@ pub mod tests {
/// Tries concurrently upserting `N_WORKERS` IDs on the same token. Then
/// verifies each one have been successfully upserted.
#[test]
fn test_concurrent_upsert() {
fn concurrent_upsert() {
let db = InMemoryDb::default();
let mut rng = CsRng::from_entropy();
let mut tok = Token::default();
Expand Down
4 changes: 2 additions & 2 deletions src/dx_enc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ mod structs;
mod vera;

use crate::DbInterface;
pub use structs::{Dx, Edx, TagSet, Token, TokenSet};
// pub use vera::Vera;
pub use structs::{Dx, Edx, Tag, TagSet, Token, TokenSet};
pub use vera::Vera;

#[async_trait(?Send)]
pub trait DynRhDxEnc<const VALUE_LENGTH: usize>: Sized {
Expand Down
76 changes: 74 additions & 2 deletions src/dx_enc/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,78 @@ use std::{
};

use base64::engine::{general_purpose::STANDARD, Engine};
use cosmian_crypto_core::reexport::rand_core::CryptoRngCore;

use crate::CoreError;

/// Byte length of Vera's tags.
const TAG_LENGTH: usize = 16;

#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
pub struct Tag([u8; TAG_LENGTH]);

impl Tag {
pub const LENGTH: usize = TAG_LENGTH;

pub fn random(rng: &mut impl CryptoRngCore) -> Self {
let mut tag = Self::default();
rng.fill_bytes(&mut tag);
tag
}
}

impl AsRef<[u8]> for Tag {
fn as_ref(&self) -> &[u8] {
&self
}
}
impl Deref for Tag {
type Target = [u8];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Tag {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl Display for Tag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", STANDARD.encode(self))
}
}

impl From<[u8; Tag::LENGTH]> for Tag {
fn from(bytes: [u8; Tag::LENGTH]) -> Self {
Self(bytes)
}
}

impl From<Tag> for [u8; Tag::LENGTH] {
fn from(tag: Tag) -> Self {
tag.0
}
}

impl TryFrom<&[u8]> for Tag {
type Error = CoreError;

fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
<[u8; Self::LENGTH]>::try_from(bytes)
.map_err(|_| {
Self::Error::Conversion(format!(
"incorrect byte length: expected {}, found {}",
Self::LENGTH,
bytes.len()
))
})
.map(Self)
}
}

// This type is needed to add automatic logging (we need all argument types to
// implement `Display`).
Expand Down Expand Up @@ -170,9 +242,9 @@ impl<const VALUE_LENGTH: usize, Tag: Hash + PartialEq + Eq + Display, Item: Disp
for Dx<VALUE_LENGTH, Tag, Item>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Dictionary: {{")?;
writeln!(f, "Dictionary: {{")?;
for (tag, value) in self.0.iter() {
writeln!(f, " '{tag}': {value}")?;
writeln!(f, "'{tag}': {value}")?;
}
writeln!(f, "}}")
}
Expand Down
53 changes: 21 additions & 32 deletions src/dx_enc/vera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ use crate::{CoreError, DbInterface, Error, MIN_SEED_LENGTH};

use super::{
primitives::{Dem, Kmac},
CsRhDxEnc, Dx, DynRhDxEnc, Edx, TagSet, Token,
CsRhDxEnc, Dx, DynRhDxEnc, Edx, Tag, TagSet, Token,
};

/// Byte length of Vera's tags.
pub const TAG_LENGTH: usize = 16;

/// Vera is a CS-RH-DX-Enc scheme: it interacts with a DB to securely store a
/// dictionary (DX).
///
Expand All @@ -39,7 +36,7 @@ impl<
const TOKEN_INFO: &'static [u8] = b"Token derivation info.";

/// Returns the token associated to the given tag.
fn tokenize(&self, tag: &<Self as DynRhDxEnc<VALUE_LENGTH>>::Tag) -> Token {
fn tokenize(&self, tag: &Tag) -> Token {
self.kmac.hash(tag, Self::TOKEN_INFO)
}

Expand All @@ -58,7 +55,7 @@ impl<
// TODO: zeroize DX here.
let ctx = self
.dem
.encrypt(&[&tag.as_slice(), val.into().as_slice()].concat(), &tok)?;
.encrypt(&[&tag, val.into().as_slice()].concat(), &tok)?;
Ok((tok, ctx))
})
.collect()
Expand All @@ -79,16 +76,15 @@ impl<
edx.iter()
.map(|(tok, ctx)| {
let ptx = self.dem.decrypt(ctx, tok)?;
if ptx.len() != TAG_LENGTH + VALUE_LENGTH {
if ptx.len() != Tag::LENGTH + VALUE_LENGTH {
Err(CoreError::Crypto(format!(
"invalid length for decrypted EDX value: found {} while {} was expected",
"invalid length for decrypted EDX value: expected {}, found {}",
Tag::LENGTH + VALUE_LENGTH,
ptx.len(),
TAG_LENGTH + VALUE_LENGTH
)))
} else {
let tag = <Self as DynRhDxEnc<VALUE_LENGTH>>::Tag::try_from(&ptx[..TAG_LENGTH])
.expect("above check ensures length is correct");
let val = <[u8; VALUE_LENGTH]>::try_from(&ptx[TAG_LENGTH..])
let tag = Tag::try_from(&ptx[..Tag::LENGTH])?;
let val = <[u8; VALUE_LENGTH]>::try_from(&ptx[Tag::LENGTH..])
.expect("above check ensures length is correct");
Ok((tag, val.into()))
}
Expand All @@ -106,7 +102,7 @@ impl<
{
type Error = Error<DbConnection::Error>;
type DbConnection = DbConnection;
type Tag = [u8; TAG_LENGTH];
type Tag = Tag;
type Item = Item;

fn setup(seed: &[u8], connection: DbConnection) -> Result<Self, Self::Error> {
Expand Down Expand Up @@ -158,8 +154,7 @@ impl<
const VALUE_LENGTH: usize,
DbConnection: DbInterface + Clone,
Item: From<[u8; VALUE_LENGTH]> + Into<[u8; VALUE_LENGTH]>,
> CsRhDxEnc<TAG_LENGTH, VALUE_LENGTH, [u8; TAG_LENGTH]>
for Vera<VALUE_LENGTH, DbConnection, Item>
> CsRhDxEnc<{ Tag::LENGTH }, VALUE_LENGTH, Tag> for Vera<VALUE_LENGTH, DbConnection, Item>
{
async fn insert(
&self,
Expand Down Expand Up @@ -220,7 +215,7 @@ mod tests {

use cosmian_crypto_core::CsRng;
use futures::executor::block_on;
use rand::{RngCore, SeedableRng};
use rand::SeedableRng;

use crate::{InMemoryDb, InMemoryDbError};

Expand All @@ -233,15 +228,14 @@ mod tests {
/// Tries inserting `N_WORKERS` data using random tokens. Then verifies the
/// inserted, dumped and fetched DX are identical.
#[test]
fn test_insert_then_dump_and_fetch() {
fn insert_then_dump_and_fetch() {
let mut rng = CsRng::from_entropy();
let db = InMemoryDb::default();
let seed = Secret::<32>::random(&mut rng);
let vera = Vera::<VALUE_LENGTH, InMemoryDb, Item>::setup(&*seed, db).unwrap();
let inserted_dx = (0..N_WORKERS)
.map(|i| {
let mut tag = [0; TAG_LENGTH];
rng.fill_bytes(&mut tag);
let tag = Tag::random(&mut rng);
let data = [i as u8];
let rejected_items =
block_on(<Vera<VALUE_LENGTH, InMemoryDb, Item> as DynRhDxEnc<
Expand Down Expand Up @@ -270,7 +264,7 @@ mod tests {

fn concurrent_worker_upserter(
vera: &Vera<VALUE_LENGTH, InMemoryDb, Item>,
tags: &[[u8; TAG_LENGTH]],
tags: &[Tag],
id: u8,
) -> Result<(), Error<InMemoryDbError>> {
if tags.is_empty() {
Expand All @@ -282,9 +276,9 @@ mod tests {
// First tries to insert the worker ID for the first tag.
let (mut dx_cur, mut edx_cur) =
block_on(<Vera<VALUE_LENGTH, InMemoryDb, Item> as CsRhDxEnc<
TAG_LENGTH,
{ Tag::LENGTH },
VALUE_LENGTH,
[u8; TAG_LENGTH],
Tag,
>>::insert(vera, dx_new.clone()))?;

// Retries upserting with the current EDX state until it succeeds.
Expand Down Expand Up @@ -315,18 +309,14 @@ mod tests {
///
/// Then verifies each worker ID were successfully inserted.
#[test]
fn test_concurrent_upsert() {
fn concurrent_upsert() {
let mut rng = CsRng::from_entropy();
let db = InMemoryDb::default();
let seed = Secret::<32>::random(&mut rng);

// Generate a pool of tags, one tag per worker.
let tags = (0..N_WORKERS)
.map(|_| {
let mut tag = [0; TAG_LENGTH];
rng.fill_bytes(&mut tag);
tag
})
.map(|_| Tag::random(&mut rng))
.collect::<Vec<_>>();

let handles = (0..N_WORKERS)
Expand All @@ -336,7 +326,7 @@ mod tests {
let tags = tags.clone();
spawn(move || -> Result<(), Error<InMemoryDbError>> {
let vera = Vera::<VALUE_LENGTH, InMemoryDb, Item>::setup(&*seed, db).unwrap();
concurrent_worker_upserter(&vera, tags.as_slice(), i as u8)
concurrent_worker_upserter(&vera, &tags, i as u8)
})
})
.collect::<Vec<_>>();
Expand All @@ -346,9 +336,8 @@ mod tests {
}

let vera = Vera::<VALUE_LENGTH, InMemoryDb, Item>::setup(&*seed, db).unwrap();

let dx = block_on(vera.dump()).unwrap();
let stored_ids = dx.values().copied().collect::<HashSet<Item>>();
let stored_dx = block_on(vera.dump()).unwrap();
let stored_ids = stored_dx.values().copied().collect::<HashSet<Item>>();
assert_eq!(
stored_ids,
(0..N_WORKERS as u8)
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mod parameters;
#[cfg(any(test, feature = "in_memory"))]
pub use db::tests::{InMemoryDb, InMemoryDbError};
pub use db::DbInterface;
pub use dx_enc::{CsRhDxEnc, DynRhDxEnc};
pub use dx_enc::{CsRhDxEnc, DynRhDxEnc, Vera};
pub use error::{CoreError, DbInterfaceErrorTrait, Error};

// pub use mm_enc::{CsRhMmEnc, Findex};
Expand Down
Loading

0 comments on commit 546f709

Please sign in to comment.