Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circuit oram/dependency inject evictor #37

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
89233d8
Move Evictor to its own module
wjuan-mob Jul 28, 2022
0472654
Adding clarifying information for the Evictor module
wjuan-mob Jul 28, 2022
44c78c5
Refactor path_oram to take an evictor creator and add deterministic e…
wjuan-mob Jul 29, 2022
3070244
Add clarifying comments, Shortcut deterministic get next branch to av…
wjuan-mob Jul 29, 2022
39f1378
Fix formatting of use statements
wjuan-mob Aug 12, 2022
a21c6a3
Add clarification around deterministic get next branch to evict
wjuan-mob Aug 12, 2022
7661569
Remove dead code
wjuan-mob Aug 12, 2022
2e3b3c9
Update mc-oblivious-ram/src/evictor/mod.rs
wjuan-mob Aug 23, 2022
19efeaa
Update mc-oblivious-ram/src/evictor/mod.rs
wjuan-mob Aug 23, 2022
3b5391f
Remove empty spaces from use statements to allow fmt to collapse them…
wjuan-mob Aug 23, 2022
9293571
Fix accidental delete of imports in previous commit
wjuan-mob Aug 23, 2022
d343ac2
Merge commit '2e3b3c96101870d413c9adbc95bc57f7152a8387' into CircuitO…
wjuan-mob Aug 26, 2022
fd74965
Merge commit '19efeaa24d8fe793d2393e634814140a51701474' into CircuitO…
wjuan-mob Aug 26, 2022
2feb55e
Merge branch 'CircuitOram/DependencyInjectEvictor' of github.com:wjua…
wjuan-mob Aug 26, 2022
0633212
Clarify comments about reverse lexicographic order
wjuan-mob Sep 2, 2022
c2df6a6
Clarify tree size vs tree depth
wjuan-mob Sep 2, 2022
554a178
Remove size parameter from EvictorCreator and rename num_bits_needed,…
wjuan-mob Sep 2, 2022
e0d485c
Update mc-oblivious-ram/src/evictor/mod.rs
wjuan-mob Sep 2, 2022
363f6cf
Rename evict to evictor
wjuan-mob Sep 2, 2022
b6b11a3
Merge branch 'CircuitOram/DependencyInjectEvictor' of github.com:wjua…
wjuan-mob Sep 2, 2022
31ab6bb
Update mc-oblivious-ram/src/evictor/mod.rs
wjuan-mob Sep 2, 2022
35b1e2f
Format evictor.
wjuan-mob Sep 2, 2022
7e19573
Add backticks around input variable names
wjuan-mob Sep 2, 2022
29f028b
Add clarifying comment on why path oram does not require additional b…
wjuan-mob Sep 2, 2022
e219574
Merge remote-tracking branch 'shared/feature/CircuitOram' into Circui…
wjuan-mob Sep 8, 2022
7345e17
Refactor evictor/mod.rs to evictor.r
wjuan-mob Sep 8, 2022
e07b60e
Update no-asm test for rename of evict-> evictor
wjuan-mob Sep 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
231 changes: 215 additions & 16 deletions mc-oblivious-ram/src/evictor.rs
Expand Up @@ -6,23 +6,71 @@
//! include path ORAM and circuit ORAM. These strategies will be used for
//! evicting stash elements to the tree ORAM.

use crate::path_oram::{BranchCheckout, MetaSize};
use aligned_cmov::{
typenum::{PartialDiv, Prod, Unsigned, U64, U8},
A64Bytes, A8Bytes, ArrayLength,
};

use balanced_tree_index::TreeIndex;
use core::ops::Mul;
use rand_core::{CryptoRng, RngCore};

use crate::path_oram::{BranchCheckout, MetaSize};
/// Selects branches in reverse lexicographic order, where the most significant
/// digit of the branch is always 1, corresponding to the leaf node that
/// represents that branch. Reverse lexicographic ordering only on the
/// `num_bits_to_be_reversed` E.g. for a depth of 3:
/// 100, 110, 101, 111
/// `num_bits_to_be_reversed` corresponds to the number of possible branches
/// that need to be explored, and is 1 less than the number of bits in the leaf
/// node. `iteration` i corresponds to the ith branch in reverse lexicographic
/// order.
fn deterministic_get_next_branch_to_evict(num_bits_to_be_reversed: u32, iteration: u64) -> u64 {
// Return 1 if the number of bits needed is 0. Calculation furtherdown would
// overflow, and shortcutting here does not leak information because the
// number of bits is structural information rather than query specific.
if num_bits_to_be_reversed == 0 {
return 1;
}
// This is the first index at which leafs exist, the most significant digit
// of all leafs is 1.
let leaf_significant_index: u64 = 1 << (num_bits_to_be_reversed);
let test_position: u64 =
((iteration).reverse_bits() >> (64 - num_bits_to_be_reversed)) % leaf_significant_index;
leaf_significant_index + test_position
}

/// Evictor trait conceptually is a mechanism for moving stash elements into
/// the oram.
pub trait Evictor<ValueSize, Z>
/// An evictor that implements a random branch selection and the path oram
/// eviction strategy
pub struct PathOramRandomEvictor<RngType>
where
RngType: RngCore + CryptoRng + Send + Sync + 'static,
{
rng: RngType,
number_of_additional_branches_to_evict: usize,
branches_evicted: u64,
tree_height: u32,
}

impl<RngType> BranchSelector for PathOramRandomEvictor<RngType>
where
RngType: RngCore + CryptoRng + Send + Sync + 'static,
{
fn get_next_branch_to_evict(&mut self) -> u64 {
self.branches_evicted += 1;
1u64.random_child_at_height(self.tree_height, &mut self.rng)
}

fn get_number_of_additional_branches_to_evict(&self) -> usize {
self.number_of_additional_branches_to_evict
}
}
impl<ValueSize, Z, RngType> EvictionStrategy<ValueSize, Z> for PathOramRandomEvictor<RngType>
where
ValueSize: ArrayLength<u8> + PartialDiv<U8> + PartialDiv<U64>,
Z: Unsigned + Mul<ValueSize> + Mul<MetaSize>,
Prod<Z, ValueSize>: ArrayLength<u8> + PartialDiv<U8>,
Prod<Z, MetaSize>: ArrayLength<u8> + PartialDiv<U8>,
RngType: RngCore + CryptoRng + Send + Sync + 'static,
{
/// Method that takes a branch and a stash and moves elements from the
/// stash into the branch.
Expand All @@ -31,10 +79,48 @@ where
stash_data: &mut [A64Bytes<ValueSize>],
stash_meta: &mut [A8Bytes<MetaSize>],
branch: &mut BranchCheckout<ValueSize, Z>,
);
) {
path_oram_eviction_strategy::<ValueSize, Z>(stash_data, stash_meta, branch);
}
}

/// An evictor that implements a deterministic branch selection in reverse
/// lexicographic order and using the path oram eviction strategy
pub struct PathOramDeterministicEvictor {
number_of_additional_branches_to_evict: usize,
branches_evicted: u64,
tree_height: u32,
tree_breadth: u64,
}
impl PathOramDeterministicEvictor {
/// Create a new deterministic branch selector that will select
/// `number_of_additional_branches_to_evict`: branches per access in
/// excess of branch with accessed element.
/// `tree height`: corresponds to the height of tree
pub fn new(number_of_additional_branches_to_evict: usize, tree_height: u32) -> Self {
Self {
number_of_additional_branches_to_evict,
tree_height,
tree_breadth: 2u64 ^ (tree_height as u64),
branches_evicted: 0,
}
}
}
pub struct PathOramEvict {}
impl<ValueSize, Z> Evictor<ValueSize, Z> for PathOramEvict

impl BranchSelector for PathOramDeterministicEvictor {
fn get_next_branch_to_evict(&mut self) -> u64 {
//The height of the root is 0, so the number of bits needed for the leaves is
// just the height
let iteration = self.branches_evicted;
self.branches_evicted = (self.branches_evicted + 1) % self.tree_breadth;
deterministic_get_next_branch_to_evict(self.tree_height, iteration)
}

fn get_number_of_additional_branches_to_evict(&self) -> usize {
self.number_of_additional_branches_to_evict
}
}
impl<ValueSize, Z> EvictionStrategy<ValueSize, Z> for PathOramDeterministicEvictor
where
ValueSize: ArrayLength<u8> + PartialDiv<U8> + PartialDiv<U64>,
Z: Unsigned + Mul<ValueSize> + Mul<MetaSize>,
Expand All @@ -47,16 +133,129 @@ where
stash_meta: &mut [A8Bytes<MetaSize>],
branch: &mut BranchCheckout<ValueSize, Z>,
) {
branch.pack();
//Greedily place elements of the stash into the branch as close to the leaf as
// they can go.
for idx in 0..stash_data.len() {
branch.ct_insert(1.into(), &stash_data[idx], &mut stash_meta[idx]);
path_oram_eviction_strategy::<ValueSize, Z>(stash_data, stash_meta, branch);
}
}

/// Eviction algorithm defined in path oram. Packs the branch and greedily
/// tries to evict everything from the stash into the checked out branch
fn path_oram_eviction_strategy<ValueSize, Z>(
stash_data: &mut [A64Bytes<ValueSize>],
stash_meta: &mut [A8Bytes<MetaSize>],
branch: &mut BranchCheckout<ValueSize, Z>,
) where
ValueSize: ArrayLength<u8> + PartialDiv<U8> + PartialDiv<U64>,
Z: Unsigned + Mul<ValueSize> + Mul<MetaSize>,
Prod<Z, ValueSize>: ArrayLength<u8> + PartialDiv<U8>,
Prod<Z, MetaSize>: ArrayLength<u8> + PartialDiv<U8>,
{
branch.pack();
//Greedily place elements of the stash into the branch as close to the leaf as
// they can go.
for idx in 0..stash_data.len() {
branch.ct_insert(1.into(), &stash_data[idx], &mut stash_meta[idx]);
}
}

pub trait BranchSelector {
/// Returns the leaf index of the next branch to call
/// [EvictionStrategy::evict_from_stash_to_branch] on.
fn get_next_branch_to_evict(&mut self) -> u64;

/// Returns the number of branches to call
/// [EvictionStrategy::evict_from_stash_to_branch] on.
fn get_number_of_additional_branches_to_evict(&self) -> usize;
}

/// Evictor trait conceptually is a mechanism for moving stash elements into
/// the oram.
pub trait EvictionStrategy<ValueSize, Z>
where
ValueSize: ArrayLength<u8> + PartialDiv<U8> + PartialDiv<U64>,
Z: Unsigned + Mul<ValueSize> + Mul<MetaSize>,
Prod<Z, ValueSize>: ArrayLength<u8> + PartialDiv<U8>,
Prod<Z, MetaSize>: ArrayLength<u8> + PartialDiv<U8>,
{
/// Method that takes a branch and a stash and moves elements from the
/// stash into the branch.
fn evict_from_stash_to_branch(
&self,
stash_data: &mut [A64Bytes<ValueSize>],
stash_meta: &mut [A8Bytes<MetaSize>],
branch: &mut BranchCheckout<ValueSize, Z>,
);
}

/// A factory which creates an Evictor
pub trait EvictorCreator<ValueSize, Z>
where
ValueSize: ArrayLength<u8> + PartialDiv<U8> + PartialDiv<U64>,
Z: Unsigned + Mul<ValueSize> + Mul<MetaSize>,
Prod<Z, ValueSize>: ArrayLength<u8> + PartialDiv<U8>,
Prod<Z, MetaSize>: ArrayLength<u8> + PartialDiv<U8>,
{
type Output: EvictionStrategy<ValueSize, Z> + BranchSelector + Send + Sync + 'static;

/// Creates an eviction strategy
/// `height`: height of the tree eviction will be called on, impacts branch
/// selection.
fn create(&self, height: u32) -> Self::Output;
}

/// A factory which creates an PathOramDeterministicEvictor that evicts from the
/// stash into an additional `number_of_additional_branches_to_evict` branches
/// in addition to the currently checked out branch in reverse lexicographic
/// order.
pub struct PathOramDeterministicEvictorCreator {
number_of_additional_branches_to_evict: usize,
}
impl PathOramDeterministicEvictorCreator {
/// Create a factory for a deterministic branch selector that will evict
/// `number_of_additional_branches_to_evict` branches per access
pub fn new(number_of_additional_branches_to_evict: usize) -> Self {
Self {
number_of_additional_branches_to_evict,
}
}
}
impl PathOramEvict {
pub fn new() -> Self {
Self {}

impl<ValueSize, Z> EvictorCreator<ValueSize, Z> for PathOramDeterministicEvictorCreator
where
ValueSize: ArrayLength<u8> + PartialDiv<U8> + PartialDiv<U64>,
Z: Unsigned + Mul<ValueSize> + Mul<MetaSize>,
Prod<Z, ValueSize>: ArrayLength<u8> + PartialDiv<U8>,
Prod<Z, MetaSize>: ArrayLength<u8> + PartialDiv<U8>,
{
type Output = PathOramDeterministicEvictor;

fn create(&self, height: u32) -> Self::Output {
PathOramDeterministicEvictor::new(self.number_of_additional_branches_to_evict, height)
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
// Check that deterministic oram correctly chooses leaf values
fn test_deterministic_oram_get_branches_to_evict() {
let test_branch = deterministic_get_next_branch_to_evict(3, 0);
assert_eq!(test_branch, 8);
let test_branch = deterministic_get_next_branch_to_evict(3, 1);
assert_eq!(test_branch, 12);
let test_branch = deterministic_get_next_branch_to_evict(3, 2);
assert_eq!(test_branch, 10);
let test_branch = deterministic_get_next_branch_to_evict(3, 3);
assert_eq!(test_branch, 14);
let test_branch = deterministic_get_next_branch_to_evict(3, 4);
assert_eq!(test_branch, 9);
let test_branch = deterministic_get_next_branch_to_evict(3, 5);
assert_eq!(test_branch, 13);
let test_branch = deterministic_get_next_branch_to_evict(3, 6);
assert_eq!(test_branch, 11);
let test_branch = deterministic_get_next_branch_to_evict(3, 7);
assert_eq!(test_branch, 15);
let test_branch = deterministic_get_next_branch_to_evict(3, 8);
assert_eq!(test_branch, 8);
}
}
29 changes: 25 additions & 4 deletions mc-oblivious-ram/src/lib.rs
Expand Up @@ -33,6 +33,7 @@ mod position_map;
pub use position_map::{ORAMU32PositionMap, TrivialPositionMap, U32PositionMapCreator};

mod evictor;
pub use evictor::{PathOramDeterministicEvictor, PathOramDeterministicEvictorCreator};

mod path_oram;
pub use path_oram::PathORAM;
Expand All @@ -56,14 +57,24 @@ where
R: RngCore + CryptoRng + Send + Sync + 'static,
SC: ORAMStorageCreator<U4096, U32>,
{
type Output = PathORAM<U2048, U2, SC::Output, R>;
type Output = PathORAM<U2048, U2, SC::Output, R, PathOramDeterministicEvictor>;

fn create<M: 'static + FnMut() -> R>(
size: u64,
stash_size: usize,
rng_maker: &mut M,
) -> Self::Output {
PathORAM::new::<U32PositionMapCreator<U2048, R, Self>, SC, M>(size, stash_size, rng_maker)
// Number of additional branches to evict is 0 because path oram densely packs
// the branch which contains the accessed element, and thus no additional
// branches need to be evicted to maintain performance.
let evictor_factory = PathOramDeterministicEvictorCreator::new(0);

PathORAM::new::<
U32PositionMapCreator<U2048, R, Self>,
SC,
M,
PathOramDeterministicEvictorCreator,
>(size, stash_size, rng_maker, evictor_factory)
}
}

Expand All @@ -83,14 +94,24 @@ where
R: RngCore + CryptoRng + Send + Sync + 'static,
SC: ORAMStorageCreator<U4096, U64>,
{
type Output = PathORAM<U1024, U4, SC::Output, R>;
type Output = PathORAM<U1024, U4, SC::Output, R, PathOramDeterministicEvictor>;

fn create<M: 'static + FnMut() -> R>(
size: u64,
stash_size: usize,
rng_maker: &mut M,
) -> Self::Output {
PathORAM::new::<U32PositionMapCreator<U1024, R, Self>, SC, M>(size, stash_size, rng_maker)
// Number of additional branches to evict is 0 because path oram densely packs
// the branch which contains the accessed element, and thus no additional
// branches need to be evicted to maintain performance.
let evictor_factory = PathOramDeterministicEvictorCreator::new(0);

PathORAM::new::<
U32PositionMapCreator<U1024, R, Self>,
SC,
M,
PathOramDeterministicEvictorCreator,
>(size, stash_size, rng_maker, evictor_factory)
}
}

Expand Down