Skip to content

Commit

Permalink
feat: add partial coordinates
Browse files Browse the repository at this point in the history
  • Loading branch information
tbrezot committed Jan 16, 2024
1 parent 3725319 commit b875ca3
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 362 deletions.
93 changes: 21 additions & 72 deletions src/abe_policy/access_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ use std::{
ops::{BitAnd, BitOr},
};

use crate::{
abe_policy::{Attribute, Policy},
Error,
};
use crate::{abe_policy::Attribute, Error};

/// An `AccessPolicy` is a boolean expression over attributes.
///
Expand All @@ -17,7 +14,6 @@ pub enum AccessPolicy {
Attr(Attribute),
And(Box<AccessPolicy>, Box<AccessPolicy>),
Or(Box<AccessPolicy>, Box<AccessPolicy>),
All, // indicates we want the disjunction of all attributes
}

impl PartialEq for AccessPolicy {
Expand All @@ -28,7 +24,7 @@ impl PartialEq for AccessPolicy {
if left_to_u32 != right_to_u32 {
false
} else {
self.attributes() == other.attributes()
self.ordered_attributes() == other.ordered_attributes()
}
}
}
Expand Down Expand Up @@ -71,7 +67,6 @@ impl AccessPolicy {
}
Self::And(l, r) => l.to_u32(attribute_mapping) * r.to_u32(attribute_mapping),
Self::Or(l, r) => l.to_u32(attribute_mapping) + r.to_u32(attribute_mapping),
Self::All => 0,
}
}

Expand Down Expand Up @@ -319,88 +314,42 @@ impl AccessPolicy {
}
}

/// Retrieves all the attributes present in this access policy.
///
/// The attributes are sorted. This is useful for comparisons.
/// Returns the sorted sequence of attributes used in the access policy.
#[must_use]
pub fn attributes(&self) -> Vec<Attribute> {
let mut attributes = self._attributes();
attributes.sort();
pub fn ordered_attributes(&self) -> Vec<Attribute> {
let mut attributes = self.clone().into_attributes();
attributes.sort_unstable();
attributes
}

fn _attributes(&self) -> Vec<Attribute> {
/// Returns the sequence of attributes used in the access policy.
pub fn into_attributes(self) -> Vec<Attribute> {
match self {
Self::Attr(att) => vec![att.clone()],
Self::And(a1, a2) | Self::Or(a1, a2) => {
let mut v = Self::_attributes(a1);
v.extend(Self::_attributes(a2));
v
Self::Attr(att) => vec![att],
Self::And(lhs, rhs) | Self::Or(lhs, rhs) => {
[lhs.into_attributes(), rhs.into_attributes()].concat()
}

Self::All => vec![],
}
}

/// Returns the list of attribute combinations that can be built from the
/// given access policy. It is an OR expression of AND expressions.
///
/// - `policy` : global policy
/// - `include_lower_attributes_from_dim` : set to `true` to combine lower
/// attributes
/// from dimension with hierarchical order
pub fn to_attribute_combinations(
&self,
policy: &Policy,
include_lower_attributes_from_dim: bool,
) -> Result<Vec<Vec<Attribute>>, Error> {
/// Converts the access policy into the Disjunctive Normal Form (DNF) of its attributes.
#[must_use]
pub fn into_dnf(self) -> Vec<Vec<Attribute>> {
match self {
Self::Attr(attr) => {
let dim_parameters = policy
.dimensions
.get(&attr.dimension)
.ok_or_else(|| Error::DimensionNotFound(attr.dimension.to_string()))?;
let mut res = vec![vec![attr.clone()]];
if include_lower_attributes_from_dim && dim_parameters.is_ordered() {
// add attribute values for all attributes below the given one
for name in dim_parameters
.get_attributes_name()
.take_while(|&name| name != &attr.name)
{
res.push(vec![Attribute::new(&attr.dimension, name)]);
}
}
Ok(res)
}
Self::And(ap_left, ap_right) => {
let combinations_left =
ap_left.to_attribute_combinations(policy, include_lower_attributes_from_dim)?;
let combinations_right = ap_right
.to_attribute_combinations(policy, include_lower_attributes_from_dim)?;
Self::Attr(attr) => vec![vec![attr]],
Self::And(lhs, rhs) => {
let combinations_left = lhs.into_dnf();
let combinations_right = rhs.into_dnf();
let mut res =
Vec::with_capacity(combinations_left.len() * combinations_right.len());
for value_left in combinations_left {
for value_right in &combinations_right {
let mut combined = Vec::with_capacity(value_left.len() + value_right.len());
combined.extend_from_slice(&value_left);
combined.extend_from_slice(value_right);
res.push(combined);
res.push([value_left.as_slice(), value_right.as_slice()].concat());
}
}
Ok(res)
}
Self::Or(ap_left, ap_right) => {
let combinations_left =
ap_left.to_attribute_combinations(policy, include_lower_attributes_from_dim)?;
let combinations_right = ap_right
.to_attribute_combinations(policy, include_lower_attributes_from_dim)?;
let mut res =
Vec::with_capacity(combinations_left.len() + combinations_right.len());
res.extend(combinations_left);
res.extend(combinations_right);
Ok(res)
res
}
Self::All => Ok(vec![vec![]]),
Self::Or(lhs, rhs) => [lhs.into_dnf(), rhs.into_dnf()].concat(),
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/abe_policy/dimension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,26 @@ impl Dimension {
}
}

pub fn restrict(&self, attr_name: AttributeName) -> Result<Self, Error> {
let params = self
.get_attribute(&attr_name)
.ok_or_else(|| Error::AttributeNotFound(attr_name.to_string()))?
.clone();

match self {
Self::Ordered(attributes) => {
let mut attributes = attributes
.iter()
.take_while(|(name, _)| *name != &attr_name)
.map(|(ref_name, ref_params)| (ref_name.clone(), ref_params.clone()))
.collect::<Dict<AttributeName, AttributeParameters>>();
attributes.insert(attr_name, params);
Ok(Self::Ordered(attributes))
}
Self::Unordered(_) => Ok(Self::Unordered(HashMap::from_iter([(attr_name, params)]))),
}
}

/// Adds a new attribute to the dimension with the provided properties.
///
/// # Arguments
Expand Down
Loading

0 comments on commit b875ca3

Please sign in to comment.