Skip to content

Commit

Permalink
Merge pull request #305 from DSRCorporation/anoncreds-w3c-support-num…
Browse files Browse the repository at this point in the history
…ber-values

Support numbers values in AnonCreds W3C VC
  • Loading branch information
swcurran authored Jan 17, 2024
2 parents 009509e + 3918f85 commit 312b253
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 70 deletions.
61 changes: 43 additions & 18 deletions src/data_types/w3c/credential_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Drop for CredentialAttributes {
impl Zeroize for CredentialAttributes {
fn zeroize(&mut self) {
for attr in self.0.values_mut() {
if let CredentialAttributeValue::Attribute(attr) = attr {
if let CredentialAttributeValue::String(attr) = attr {
attr.zeroize()
}
}
Expand All @@ -43,10 +43,17 @@ impl From<&CredentialValues> for CredentialAttributes {
.0
.iter()
.map(|(attribute, values)| {
(
attribute.to_owned(),
CredentialAttributeValue::Attribute(values.raw.to_owned()),
)
if let Ok(number) = values.raw.parse::<i32>() {
(
attribute.to_string(),
CredentialAttributeValue::Number(number),
)
} else {
(
attribute.to_string(),
CredentialAttributeValue::String(values.raw.to_string()),
)
}
})
.collect(),
)
Expand All @@ -60,30 +67,35 @@ impl CredentialAttributes {

pub(crate) fn add_predicate(&mut self, attribute: String) -> crate::Result<()> {
match self.0.get(&attribute) {
Some(value) => match value {
CredentialAttributeValue::Attribute(_) => {
return Err(err_msg!("Predicate cannot be added for revealed attribute"));
Some(value) => {
match value {
CredentialAttributeValue::String(_) | CredentialAttributeValue::Number(_) => {
Err(err_msg!("Predicate cannot be added for revealed attribute"))
}
CredentialAttributeValue::Bool(_) => {
// predicate already exists
Ok(())
}
}
CredentialAttributeValue::Predicate(_) => {
// predicate already exists
return Ok(());
}
},
}
None => {
self.0
.insert(attribute, CredentialAttributeValue::Predicate(true));
.insert(attribute, CredentialAttributeValue::Bool(true));
Ok(())
}
}
Ok(())
}

pub(crate) fn encode(&self) -> crate::Result<CredentialValues> {
let mut cred_values = MakeCredentialValues::default();
for (attribute, raw_value) in self.0.iter() {
match raw_value {
CredentialAttributeValue::Attribute(raw_value) => {
CredentialAttributeValue::String(raw_value) => {
cred_values.add_raw(attribute, raw_value)?
}
CredentialAttributeValue::Number(raw_value) => {
cred_values.add_raw(attribute, raw_value.to_string())?
}
value => {
return Err(err_msg!(
"Encoding is not supported for credential value {:?}",
Expand All @@ -99,6 +111,19 @@ impl CredentialAttributes {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum CredentialAttributeValue {
Attribute(String),
Predicate(bool),
// attribute representation
String(String),
Number(i32),
// predicates representation
Bool(bool),
}

impl ToString for CredentialAttributeValue {
fn to_string(&self) -> String {
match self {
CredentialAttributeValue::String(string) => string.to_owned(),
CredentialAttributeValue::Number(number) => number.to_string(),
CredentialAttributeValue::Bool(bool) => bool.to_string(),
}
}
}
24 changes: 12 additions & 12 deletions src/services/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ pub(crate) fn verify_requested_restrictions(
})?;
let filter = gather_filter_info(identifier, schemas, cred_defs)?;

let attr_value_map: HashMap<String, Option<&str>> = if let Some(name) =
let attr_value_map: HashMap<String, Option<String>> = if let Some(name) =
info.name.as_ref()
{
let mut map = HashMap::new();
Expand All @@ -441,17 +441,17 @@ pub(crate) fn verify_requested_restrictions(
requested_proof
.revealed_attrs
.get(referent)
.map(|attr| attr.raw.as_str()),
.map(|attr| attr.raw.to_string()),
);
map
} else if let Some(names) = info.names.as_ref() {
let mut map = HashMap::new();
let mut map: HashMap<String, Option<String>> = HashMap::new();
let attrs = requested_proof
.revealed_attr_groups
.get(referent)
.ok_or_else(|| err_msg!("Proof does not have referent from proof request"))?;
for name in names {
let val = attrs.values.get(name).map(|attr| attr.raw.as_str());
let val = attrs.values.get(name).map(|attr| attr.raw.clone());
map.insert(name.clone(), val);
}
map
Expand Down Expand Up @@ -484,7 +484,7 @@ pub(crate) fn verify_requested_restrictions(
let filter = gather_filter_info(identifier, schemas, cred_defs)?;

// start with the predicate requested attribute, which is un-revealed
let mut attr_value_map = HashMap::new();
let mut attr_value_map: HashMap<String, Option<String>> = HashMap::new();
attr_value_map.insert(info.name.to_string(), None);

// include any revealed attributes for the same credential (based on sub_proof_index)
Expand All @@ -499,7 +499,7 @@ pub(crate) fn verify_requested_restrictions(
if pred_sub_proof_index == attr_sub_proof_index {
let attr_name = requested_attrs.get(attr_referent).unwrap().name.clone();
if let Some(name) = attr_name {
attr_value_map.insert(name, Some(attr_info.raw.as_str()));
attr_value_map.insert(name, Some(attr_info.raw.clone()));
}
}
}
Expand All @@ -511,7 +511,7 @@ pub(crate) fn verify_requested_restrictions(
let attr_sub_proof_index = attr_info.sub_proof_index;
if pred_sub_proof_index == attr_sub_proof_index {
for name in attr_info.values.keys() {
let raw_val = attr_info.values.get(name).unwrap().raw.as_str();
let raw_val = attr_info.values.get(name).unwrap().raw.clone();
attr_value_map.insert(name.to_string(), Some(raw_val));
}
}
Expand Down Expand Up @@ -568,7 +568,7 @@ pub(crate) fn gather_filter_info(
}

pub(crate) fn process_operator(
attr_value_map: &HashMap<String, Option<&str>>,
attr_value_map: &HashMap<String, Option<String>>,
restriction_op: &Query,
filter: &Filter,
) -> Result<()> {
Expand Down Expand Up @@ -637,7 +637,7 @@ pub(crate) fn process_operator(
}

fn process_filter(
attr_value_map: &HashMap<String, Option<&str>>,
attr_value_map: &HashMap<String, Option<String>>,
tag: &str,
tag_value: &str,
filter: &Filter,
Expand Down Expand Up @@ -695,7 +695,7 @@ fn precess_filed(filed: &str, filter_value: impl Into<String>, tag_value: &str)
}
}

fn is_attr_internal_tag(key: &str, attr_value_map: &HashMap<String, Option<&str>>) -> bool {
fn is_attr_internal_tag(key: &str, attr_value_map: &HashMap<String, Option<String>>) -> bool {
INTERNAL_TAG_MATCHER.captures(key).map_or(false, |caps| {
caps.get(1).map_or(false, |s| {
attr_value_map.contains_key(&s.as_str().to_string())
Expand All @@ -706,7 +706,7 @@ fn is_attr_internal_tag(key: &str, attr_value_map: &HashMap<String, Option<&str>
fn check_internal_tag_revealed_value(
key: &str,
tag_value: &str,
attr_value_map: &HashMap<String, Option<&str>>,
attr_value_map: &HashMap<String, Option<String>>,
) -> Result<()> {
let attr_name = INTERNAL_TAG_MATCHER
.captures(key)
Expand Down Expand Up @@ -1019,7 +1019,7 @@ mod tests {
revealed_value: Option<&str>,
) -> Result<()> {
let mut attr_value_map = HashMap::new();
attr_value_map.insert(attr.to_string(), revealed_value);
attr_value_map.insert(attr.to_string(), revealed_value.map(String::from));
process_operator(&attr_value_map, restriction_op, filter)
}

Expand Down
6 changes: 4 additions & 2 deletions src/services/w3c/credential_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ pub(crate) mod tests {
pub fn w3c_credential() -> W3CCredential {
W3CCredential::new(
issuer_id(),
CredentialAttributes::from(&cred_values()),
CredentialAttributes::try_from(&cred_values()).unwrap(),
DataIntegrityProof::new_credential_proof(&credential_signature_proof()).unwrap(),
None,
)
Expand Down Expand Up @@ -345,9 +345,11 @@ pub(crate) mod tests {

assert_eq!(w3c_credential.context, expected_context.clone());
assert_eq!(w3c_credential.type_, ANONCREDS_CREDENTIAL_TYPES.clone());

let expected_attributes = CredentialAttributes::from(&legacy_credential.values);
assert_eq!(
w3c_credential.credential_subject.attributes,
CredentialAttributes::from(&legacy_credential.values)
expected_attributes
);

let proof = w3c_credential
Expand Down
24 changes: 15 additions & 9 deletions src/services/w3c/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,31 @@ impl W3CCredential {
.ok_or_else(|| err_msg!("Credential attribute {} not found", requested_attribute))
}

pub(crate) fn get_attribute(&self, requested_attribute: &str) -> Result<(String, String)> {
pub(crate) fn get_attribute(
&self,
requested_attribute: &str,
) -> Result<(String, CredentialAttributeValue)> {
let (attribute, value) = self.get_case_insensitive_attribute(requested_attribute)?;
match value {
CredentialAttributeValue::Attribute(value) => Ok((attribute, value)),
CredentialAttributeValue::Predicate(_) => Err(err_msg!(
CredentialAttributeValue::String(_) => Ok((attribute, value)),
CredentialAttributeValue::Number(_) => Ok((attribute, value)),
CredentialAttributeValue::Bool(_) => Err(err_msg!(
"Credential attribute {} not found",
requested_attribute
)),
}
}

pub(crate) fn get_predicate(&self, requested_predicate: &str) -> Result<(String, bool)> {
pub(crate) fn get_predicate(
&self,
requested_predicate: &str,
) -> Result<(String, CredentialAttributeValue)> {
let (attribute, value) = self.get_case_insensitive_attribute(requested_predicate)?;
match value {
CredentialAttributeValue::Predicate(value) => Ok((attribute, value)),
CredentialAttributeValue::Attribute(_) => Err(err_msg!(
"Credential predicate {} not found",
requested_predicate
)),
CredentialAttributeValue::Bool(_) => Ok((attribute, value)),
CredentialAttributeValue::String(_) | CredentialAttributeValue::Number(_) => Err(
err_msg!("Credential predicate {} not found", requested_predicate),
),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/w3c/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ impl MakeCredentialAttributes {
pub fn add(&mut self, name: impl Into<String>, raw: impl Into<String>) {
self.0
.0
.insert(name.into(), CredentialAttributeValue::Attribute(raw.into()));
.insert(name.into(), CredentialAttributeValue::String(raw.into()));
}
}

Expand Down
17 changes: 10 additions & 7 deletions src/services/w3c/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,13 @@ fn check_credential_restrictions(
timestamp: None,
};
let filter = gather_filter_info(&identifier, schemas, cred_defs)?;
let mut attr_value_map: HashMap<String, Option<&str>> = HashMap::new();
let mut attr_value_map: HashMap<String, Option<String>> = HashMap::new();
for (attribute, value) in credential.credential_subject.attributes.0.iter() {
if let CredentialAttributeValue::Attribute(value) = value {
attr_value_map.insert(attribute.to_owned(), Some(value));
if let CredentialAttributeValue::String(value) = value {
attr_value_map.insert(attribute.to_owned(), Some(value.to_string()));
}
if let CredentialAttributeValue::Number(value) = value {
attr_value_map.insert(attribute.to_owned(), Some(value.to_string()));
}
}
process_operator(&attr_value_map, restrictions, &filter).map_err(err_map!(
Expand Down Expand Up @@ -194,7 +197,7 @@ fn check_requested_attribute<'a>(
.get(index)
.ok_or_else(|| err_msg!("Unable to get credential proof for index {}", index))?;

let encoded = encode_credential_attribute(&value)?;
let encoded = encode_credential_attribute(&value.to_string())?;
if verify_revealed_attribute_value(&attribute, &proof.sub_proof, &encoded).is_err() {
continue;
}
Expand Down Expand Up @@ -394,13 +397,13 @@ pub(crate) mod tests {
CredentialAttributes(HashMap::from([
(
"name".to_string(),
CredentialAttributeValue::Attribute("Alice".to_string()),
CredentialAttributeValue::String("Alice".to_string()),
),
(
"height".to_string(),
CredentialAttributeValue::Attribute("178".to_string()),
CredentialAttributeValue::String("178".to_string()),
),
("age".to_string(), CredentialAttributeValue::Predicate(true)),
("age".to_string(), CredentialAttributeValue::Bool(true)),
]))
}

Expand Down
Loading

0 comments on commit 312b253

Please sign in to comment.