From 424189eff72481153f222a405f1772889a014f69 Mon Sep 17 00:00:00 2001 From: Miroslav Kovar Date: Thu, 22 Feb 2024 06:57:51 +0100 Subject: [PATCH] Type requested credentials (#1130) Type requested credentials (#1130) * Do not convert proof req to value unnecessarily * Start typing RequestedCredentials * prover_create_proof takes RequestedCredentials * Delete _get_credential * Do not use value for cred_by_attr --------- Signed-off-by: Miroslav Kovar --- .../aries_vcx/src/common/proofs/prover/mod.rs | 4 +- .../common/proofs/prover/prover_internal.rs | 82 +++--- .../prover/state_machine.rs | 2 +- .../states/presentation_request_received.rs | 2 +- aries/aries_vcx/tests/test_verifier.rs | 222 +++++++++++------ .../src/anoncreds/anoncreds/mod.rs | 234 +++++++----------- .../src/anoncreds/base_anoncreds.rs | 4 +- .../src/anoncreds/credx_anoncreds/mod.rs | 78 ++---- .../src/data_types/messages/cred_selection.rs | 2 +- .../src/data_types/messages/presentation.rs | 20 ++ .../test_utils/src/mockdata/mock_anoncreds.rs | 4 +- justfile | 2 +- 12 files changed, 344 insertions(+), 312 deletions(-) diff --git a/aries/aries_vcx/src/common/proofs/prover/mod.rs b/aries/aries_vcx/src/common/proofs/prover/mod.rs index 19d291ea44..885b11d534 100644 --- a/aries/aries_vcx/src/common/proofs/prover/mod.rs +++ b/aries/aries_vcx/src/common/proofs/prover/mod.rs @@ -25,7 +25,7 @@ pub async fn generate_indy_proof( ledger: &impl AnoncredsLedgerRead, anoncreds: &impl BaseAnonCreds, credentials: &SelectedCredentials, - self_attested_attrs: &HashMap, + self_attested_attrs: HashMap, proof_req_data_json: PresentationRequest, ) -> VcxResult { trace!( @@ -53,7 +53,7 @@ pub async fn generate_indy_proof( .prover_create_proof( wallet, proof_req_data_json, - &requested_credentials, + requested_credentials, &settings::DEFAULT_LINK_SECRET_ALIAS.to_string(), schemas_json, credential_defs_json, diff --git a/aries/aries_vcx/src/common/proofs/prover/prover_internal.rs b/aries/aries_vcx/src/common/proofs/prover/prover_internal.rs index 9289d2875f..03730b0f98 100644 --- a/aries/aries_vcx/src/common/proofs/prover/prover_internal.rs +++ b/aries/aries_vcx/src/common/proofs/prover/prover_internal.rs @@ -5,6 +5,7 @@ use anoncreds_types::data_types::{ messages::{ cred_selection::SelectedCredentials, pres_request::{NonRevokedInterval, PresentationRequest}, + presentation::{RequestedAttribute, RequestedCredentials, RequestedPredicate}, }, }; use aries_vcx_core::{ @@ -14,10 +15,10 @@ use aries_vcx_core::{ errors::error::AriesVcxCoreErrorKind, ledger::base_ledger::AnoncredsLedgerRead, }; -use serde_json::Value; use crate::errors::error::prelude::*; +// TODO: Move to anoncreds_types #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct CredInfoProver { pub referent: String, @@ -211,9 +212,9 @@ pub async fn build_rev_states_json( pub fn build_requested_credentials_json( credentials_identifiers: &Vec, - self_attested_attrs: &HashMap, + self_attested_attrs: HashMap, proof_req: &PresentationRequest, -) -> VcxResult { +) -> VcxResult { trace!( "build_requested_credentials_json >> credentials_identifiers: {:?}, self_attested_attrs: \ {:?}, proof_req: {:?}", @@ -221,50 +222,48 @@ pub fn build_requested_credentials_json( self_attested_attrs, proof_req ); - let mut rtn: Value = json!({ - "self_attested_attributes":{}, - "requested_attributes":{}, - "requested_predicates":{} - }); - // do same for predicates and self_attested - if let Value::Object(ref mut map) = rtn["requested_attributes"] { - for cred_info in credentials_identifiers { - if proof_req - .value() - .requested_attributes - .get(&cred_info.referent) - .is_some() - { - let insert_val = json!({"cred_id": cred_info.credential_referent, "revealed": cred_info.revealed.unwrap_or(true), "timestamp": cred_info.timestamp}); - map.insert(cred_info.referent.to_owned(), insert_val); - } + + let mut rtn = RequestedCredentials::default(); + + for cred_info in credentials_identifiers { + if proof_req + .value() + .requested_attributes + .get(&cred_info.referent) + .is_some() + { + rtn.requested_attributes.insert( + cred_info.referent.to_owned(), + RequestedAttribute { + cred_id: cred_info.credential_referent.to_owned(), + timestamp: cred_info.timestamp, + revealed: cred_info.revealed.unwrap_or(true), + }, + ); } } - if let Value::Object(ref mut map) = rtn["requested_predicates"] { - for cred_info in credentials_identifiers { - if proof_req - .value() - .requested_predicates - .get(&cred_info.referent) - .is_some() - { - let insert_val = json!({"cred_id": cred_info.credential_referent, "timestamp": cred_info.timestamp}); - map.insert(cred_info.referent.to_owned(), insert_val); - } + for cred_info in credentials_identifiers { + if proof_req + .value() + .requested_predicates + .get(&cred_info.referent) + .is_some() + { + rtn.requested_predicates.insert( + cred_info.referent.to_owned(), + RequestedPredicate { + cred_id: cred_info.credential_referent.to_owned(), + timestamp: cred_info.timestamp, + }, + ); } } // handle if the attribute is not revealed - let self_attested_attrs: Value = serde_json::to_value(self_attested_attrs).map_err(|err| { - AriesVcxError::from_msg( - AriesVcxErrorKind::InvalidJson, - format!("Cannot deserialize self attested attributes: {}", err), - ) - })?; - rtn["self_attested_attributes"] = self_attested_attrs; + rtn.self_attested_attributes = self_attested_attrs; - Ok(rtn.to_string()) + Ok(rtn) } #[cfg(test)] @@ -320,6 +319,7 @@ pub mod pool_tests { #[cfg(test)] pub mod unit_tests { use aries_vcx_core::ledger::indy::pool::test_utils::get_temp_dir_path; + use serde_json::Value; use test_utils::{ constants::{ address_cred_def_id, address_schema_id, cred_def_id, schema_id, ADDRESS_CRED_DEF_ID, @@ -685,11 +685,11 @@ pub mod unit_tests { let proof_req: PresentationRequest = serde_json::from_value(proof_req).unwrap(); let requested_credential = build_requested_credentials_json( &creds, - &serde_json::from_str(&self_attested_attrs).unwrap(), + serde_json::from_str(&self_attested_attrs).unwrap(), &proof_req, ) .unwrap(); - assert_eq!(test.to_string(), requested_credential); + assert_eq!(test, serde_json::to_value(requested_credential).unwrap()); } #[tokio::test] diff --git a/aries/aries_vcx/src/protocols/proof_presentation/prover/state_machine.rs b/aries/aries_vcx/src/protocols/proof_presentation/prover/state_machine.rs index 31b01416a2..1bc84b7fd8 100644 --- a/aries/aries_vcx/src/protocols/proof_presentation/prover/state_machine.rs +++ b/aries/aries_vcx/src/protocols/proof_presentation/prover/state_machine.rs @@ -249,7 +249,7 @@ impl ProverSM { ledger, anoncreds, &credentials, - &self_attested_attrs, + self_attested_attrs, ) .await { diff --git a/aries/aries_vcx/src/protocols/proof_presentation/prover/states/presentation_request_received.rs b/aries/aries_vcx/src/protocols/proof_presentation/prover/states/presentation_request_received.rs index 4c13ee8a1d..e8c74dee9f 100644 --- a/aries/aries_vcx/src/protocols/proof_presentation/prover/states/presentation_request_received.rs +++ b/aries/aries_vcx/src/protocols/proof_presentation/prover/states/presentation_request_received.rs @@ -61,7 +61,7 @@ impl PresentationRequestReceived { ledger: &impl AnoncredsLedgerRead, anoncreds: &impl BaseAnonCreds, credentials: &SelectedCredentials, - self_attested_attrs: &HashMap, + self_attested_attrs: HashMap, ) -> VcxResult { let proof_req_data_json = serde_json::from_str(&get_attach_as_string!( &self diff --git a/aries/aries_vcx/tests/test_verifier.rs b/aries/aries_vcx/tests/test_verifier.rs index bb26974a88..13afa134f9 100644 --- a/aries/aries_vcx/tests/test_verifier.rs +++ b/aries/aries_vcx/tests/test_verifier.rs @@ -4,7 +4,9 @@ use anoncreds_types::{ data_types::messages::{ nonce::Nonce, pres_request::{AttributeInfo, PresentationRequest, PresentationRequestPayload}, - presentation::Presentation, + presentation::{ + Presentation, RequestedAttribute, RequestedCredentials, RequestedPredicate, + }, }, utils::query::Query, }; @@ -81,18 +83,35 @@ async fn create_indy_proof( "requested_predicates": json!({}), }) .to_string(); - let requested_credentials_json = json!({ - "self_attested_attributes":{ - "self_attest_3": "my_self_attested_val" - }, - "requested_attributes":{ - "address1_1": {"cred_id": cred_id, "revealed": true}, - "zip_2": {"cred_id": cred_id, "revealed": true} - }, - "requested_predicates":{} - }) - .to_string(); - + let requested_credentials_json = RequestedCredentials { + self_attested_attributes: vec![( + "self_attest_3".to_string(), + "my_self_attested_val".to_string(), + )] + .into_iter() + .collect(), + requested_attributes: vec![ + ( + "address1_1".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + ), + ( + "zip_2".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + ), + ] + .into_iter() + .collect(), + requested_predicates: Default::default(), + }; let schema_id = schema.schema_id.clone(); let schemas = json!({ schema_id: schema.schema_json, @@ -113,7 +132,7 @@ async fn create_indy_proof( .prover_create_proof( wallet_holder, serde_json::from_str(&proof_req)?, - &requested_credentials_json, + requested_credentials_json, &"main".to_string(), serde_json::from_str(&schemas)?, serde_json::from_str(&cred_defs)?, @@ -179,30 +198,53 @@ async fn create_proof_with_predicate( .to_string(); let requested_credentials_json = if include_predicate_cred { - json!({ - "self_attested_attributes":{ - "self_attest_3": "my_self_attested_val" - }, - "requested_attributes":{ - "address1_1": {"cred_id": cred_id, "revealed": true} - }, - "requested_predicates":{ - "zip_3": {"cred_id": cred_id} - } - }) - .to_string() + RequestedCredentials { + self_attested_attributes: vec![( + "self_attest_3".to_string(), + "my_self_attested_val".to_string(), + )] + .into_iter() + .collect(), + requested_attributes: vec![( + "address1_1".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + )] + .into_iter() + .collect(), + requested_predicates: vec![( + "zip_3".to_string(), + RequestedPredicate { + cred_id: cred_id.clone(), + timestamp: None, + }, + )] + .into_iter() + .collect(), + } } else { - json!({ - "self_attested_attributes":{ - "self_attest_3": "my_self_attested_val" - }, - "requested_attributes":{ - "address1_1": {"cred_id": cred_id, "revealed": true} - }, - "requested_predicates":{ - } - }) - .to_string() + RequestedCredentials { + self_attested_attributes: vec![( + "self_attest_3".to_string(), + "my_self_attested_val".to_string(), + )] + .into_iter() + .collect(), + requested_attributes: vec![( + "address1_1".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + )] + .into_iter() + .collect(), + requested_predicates: Default::default(), + } }; let schemas = json!({ @@ -224,7 +266,7 @@ async fn create_proof_with_predicate( .prover_create_proof( wallet_holder, serde_json::from_str(&proof_req)?, - &requested_credentials_json, + requested_credentials_json, &"main".to_string(), serde_json::from_str(&schemas)?, serde_json::from_str(&cred_defs)?, @@ -320,15 +362,21 @@ async fn test_pool_proof_self_attested_proof_validation() -> Result<(), Box Result<(), Box> { .prover_create_proof( &setup.wallet, proof_req_json.into(), - &json!({ - "self_attested_attributes":{ - "attribute_2": "my_self_attested_val" - }, - "requested_attributes":{ - "attribute_0": {"cred_id": cred_id, "revealed": true}, - "attribute_1": {"cred_id": cred_id, "revealed": true} - }, - "requested_predicates":{} - }) - .to_string(), + RequestedCredentials { + self_attested_attributes: vec![( + "attribute_2".to_string(), + "my_self_attested_val".to_string(), + )] + .into_iter() + .collect(), + requested_attributes: vec![ + ( + "attribute_0".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + ), + ( + "attribute_1".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + ), + ] + .into_iter() + .collect(), + requested_predicates: Default::default(), + }, &"main".to_string(), serde_json::from_str(&json!({ schema.schema_id: schema.schema_json }).to_string())?, serde_json::from_str( @@ -498,17 +564,35 @@ async fn test_pool_proof_validate_attribute() -> Result<(), Box> { .prover_create_proof( &setup.wallet, proof_req_json.into(), - &json!({ - "self_attested_attributes":{ - "attribute_2": "my_self_attested_val" - }, - "requested_attributes":{ - "attribute_0": {"cred_id": cred_id, "revealed": true}, - "attribute_1": {"cred_id": cred_id, "revealed": true} - }, - "requested_predicates":{} - }) - .to_string(), + RequestedCredentials { + self_attested_attributes: vec![( + "attribute_2".to_string(), + "my_self_attested_val".to_string(), + )] + .into_iter() + .collect(), + requested_attributes: vec![ + ( + "attribute_0".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + ), + ( + "attribute_1".to_string(), + RequestedAttribute { + cred_id: cred_id.clone(), + timestamp: None, + revealed: true, + }, + ), + ] + .into_iter() + .collect(), + requested_predicates: Default::default(), + }, &"main".to_string(), serde_json::from_str(&json!({ schema.schema_id: schema.schema_json }).to_string())?, serde_json::from_str( diff --git a/aries/aries_vcx_core/src/anoncreds/anoncreds/mod.rs b/aries/aries_vcx_core/src/anoncreds/anoncreds/mod.rs index 2432d155e6..875b70f1f6 100644 --- a/aries/aries_vcx_core/src/anoncreds/anoncreds/mod.rs +++ b/aries/aries_vcx_core/src/anoncreds/anoncreds/mod.rs @@ -50,11 +50,13 @@ use anoncreds_types::data_types::{ cred_definition_config::CredentialDefinitionConfig, cred_offer::CredentialOffer, cred_request::{CredentialRequest, CredentialRequestMetadata}, - cred_selection::{RetrievedCredentialInfo, RetrievedCredentials}, + cred_selection::{ + RetrievedCredentialForReferent, RetrievedCredentialInfo, RetrievedCredentials, + }, credential::{Credential, CredentialValues}, nonce::Nonce, pres_request::PresentationRequest, - presentation::Presentation, + presentation::{Presentation, RequestedCredentials}, revocation_state::CredentialRevocationState, }, }; @@ -73,10 +75,6 @@ use super::base_anoncreds::{ use crate::{ anoncreds::anoncreds::type_conversion::Convert, errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, - utils::{ - constants::ATTRS, - json::{AsTypeOrDeserializationError, TryGetIndex}, - }, wallet::base_wallet::{ record::Record, record_category::RecordCategory, search_filter::SearchFilter, BaseWallet, }, @@ -201,20 +199,6 @@ impl Anoncreds { Ok(ms_decimal.value().try_into().unwrap()) } - async fn _get_credential( - &self, - wallet: &impl BaseWallet, - credential_id: &str, - ) -> VcxCoreResult { - let cred_record = wallet - .get_record(RecordCategory::Cred, credential_id) - .await?; - - let credential: Credential = serde_json::from_str(cred_record.value())?; - - Ok(credential) - } - async fn _get_credentials( wallet: &impl BaseWallet, wql: &str, @@ -241,7 +225,7 @@ impl Anoncreds { async fn _get_credentials_for_proof_req_for_attr_name( &self, wallet: &impl BaseWallet, - restrictions: Option<&Value>, + restrictions: Option, attr_names: Vec, ) -> VcxCoreResult> { let mut attrs = Vec::new(); @@ -701,7 +685,7 @@ impl BaseAnonCreds for Anoncreds { &self, wallet: &impl BaseWallet, proof_req_json: PresentationRequest, - requested_credentials_json: &str, + requested_credentials_json: RequestedCredentials, link_secret_id: &LinkSecretId, schemas_json: SchemasMap, credential_defs_json: CredentialDefinitionsMap, @@ -709,11 +693,9 @@ impl BaseAnonCreds for Anoncreds { ) -> VcxCoreResult { let pres_req: AnoncredsPresentationRequest = proof_req_json.convert(())?; - let requested_credentials: Value = serde_json::from_str(requested_credentials_json)?; - let requested_attributes = (&requested_credentials).try_get("requested_attributes")?; - - let requested_predicates = (&requested_credentials).try_get("requested_predicates")?; - let self_attested_attributes = requested_credentials.get("self_attested_attributes"); + let requested_attributes = requested_credentials_json.requested_attributes; + let requested_predicates = requested_credentials_json.requested_predicates; + let self_attested_attributes = requested_credentials_json.self_attested_attributes; let schemas: HashMap = schemas_json.convert(())?; let cred_defs: HashMap = @@ -734,11 +716,9 @@ impl BaseAnonCreds for Anoncreds { > = HashMap::new(); // add cred data and referent details for each requested attribute - for (reft, detail) in requested_attributes.try_as_object()?.iter() { - let _cred_id = detail.try_get("cred_id")?; - let cred_id = _cred_id.try_as_str()?; - - let revealed = detail.try_get("revealed")?.try_as_bool()?; + for (reft, detail) in requested_attributes { + let cred_id = &detail.cred_id; + let revealed = detail.revealed; if let Some((_, _, _, req_attr_refts_revealed, _)) = proof_details_by_cred_id.get_mut(cred_id) @@ -746,10 +726,16 @@ impl BaseAnonCreds for Anoncreds { // mapping made for this credential already, add reft and its revealed status req_attr_refts_revealed.push((reft.to_string(), revealed)); } else { - let credential = self._get_credential(wallet, cred_id).await?; + let credential = self + .get_wallet_record_value(wallet, RecordCategory::Cred, cred_id) + .await?; - let (timestamp, rev_state) = - get_rev_state(cred_id, &credential, detail, revoc_states_json.as_ref())?; + let (timestamp, rev_state) = get_rev_state( + cred_id, + &credential, + detail.timestamp, + revoc_states_json.as_ref(), + )?; proof_details_by_cred_id.insert( cred_id.to_string(), @@ -765,18 +751,23 @@ impl BaseAnonCreds for Anoncreds { } // add cred data and referent details for each requested predicate - for (reft, detail) in requested_predicates.try_as_object()?.iter() { - let _cred_id = detail.try_get("cred_id")?; - let cred_id = _cred_id.try_as_str()?; + for (reft, detail) in requested_predicates { + let cred_id = &detail.cred_id; if let Some((_, _, _, _, req_preds_refts)) = proof_details_by_cred_id.get_mut(cred_id) { // mapping made for this credential already, add reft req_preds_refts.push(reft.to_string()); } else { - let credential = self._get_credential(wallet, cred_id).await?; + let credential = self + .get_wallet_record_value(wallet, RecordCategory::Cred, cred_id) + .await?; - let (timestamp, rev_state) = - get_rev_state(cred_id, &credential, detail, revoc_states_json.as_ref())?; + let (timestamp, rev_state) = get_rev_state( + cred_id, + &credential, + detail.timestamp, + revoc_states_json.as_ref(), + )?; proof_details_by_cred_id.insert( cred_id.to_string(), @@ -810,30 +801,12 @@ impl BaseAnonCreds for Anoncreds { } } - // create self_attested by iterating thru self_attested_value - let self_attested = if let Some(self_attested_value) = self_attested_attributes { - let mut self_attested_map: HashMap = HashMap::new(); - let self_attested_obj = self_attested_value.try_as_object()?.clone(); - let self_attested_iter = self_attested_obj.iter(); - for (k, v) in self_attested_iter { - self_attested_map.insert(k.to_string(), v.try_as_str()?.to_string()); - } - - if self_attested_map.is_empty() { - None - } else { - Some(self_attested_map) - } - } else { - None - }; - let link_secret = self.get_link_secret(wallet, link_secret_id).await?; let presentation = anoncreds::prover::create_presentation( &pres_req, present_credentials, - self_attested, + Some(self_attested_attributes), &link_secret, &schemas, &cred_defs, @@ -847,7 +820,9 @@ impl BaseAnonCreds for Anoncreds { wallet: &impl BaseWallet, cred_id: &CredentialId, ) -> VcxCoreResult { - let cred = self._get_credential(wallet, cred_id).await?; + let cred = self + .get_wallet_record_value(wallet, RecordCategory::Cred, cred_id) + .await?; _make_cred_info(cred_id, &cred) } @@ -873,96 +848,80 @@ impl BaseAnonCreds for Anoncreds { wallet: &impl BaseWallet, proof_request_json: PresentationRequest, ) -> VcxCoreResult { - let proof_req_v: Value = serde_json::to_value(proof_request_json).map_err(|e| { - AriesVcxCoreError::from_msg(AriesVcxCoreErrorKind::InvalidProofRequest, e) - })?; - - let requested_attributes = proof_req_v.get("requested_attributes"); - let requested_attributes = if let Some(requested_attributes) = requested_attributes { - Some(requested_attributes.try_as_object()?.clone()) - } else { - None - }; - let requested_predicates = proof_req_v.get("requested_predicates"); - let requested_predicates = if let Some(requested_predicates) = requested_predicates { - Some(requested_predicates.try_as_object()?.clone()) - } else { - None - }; - - // handle special case of "empty because json is bad" vs "empty because no attributes - // sepected" - if requested_attributes.is_none() && requested_predicates.is_none() { - return Err(AriesVcxCoreError::from_msg( - AriesVcxCoreErrorKind::InvalidAttributesStructure, - "Invalid Json Parsing of Requested Attributes Retrieved From Libindy", - )); - } + let requested_attributes = &proof_request_json.value().requested_attributes; + let requested_predicates = &proof_request_json.value().requested_predicates; let mut referents: HashSet = HashSet::new(); - if let Some(requested_attributes) = &requested_attributes { - requested_attributes.iter().for_each(|(k, _)| { - referents.insert(k.to_string()); - }) - }; - if let Some(requested_predicates) = &requested_predicates { - requested_predicates.iter().for_each(|(k, _)| { - referents.insert(k.to_string()); - }); - } + requested_attributes.iter().for_each(|(k, _)| { + referents.insert(k.to_string()); + }); + + requested_predicates.iter().for_each(|(k, _)| { + referents.insert(k.to_string()); + }); - let mut cred_by_attr: Value = json!({}); + let mut cred_by_attr = RetrievedCredentials::default(); for reft in referents { - let requested_val = requested_attributes - .as_ref() - .and_then(|req_attrs| req_attrs.get(&reft)) - .or_else(|| { - requested_predicates - .as_ref() - .and_then(|req_preds| req_preds.get(&reft)) - }) - .ok_or(AriesVcxCoreError::from_msg( - // should not happen - AriesVcxCoreErrorKind::InvalidState, - format!("Unknown referent: {}", reft), - ))?; - - let name = requested_val.get("name"); - let names = requested_val.get("names").and_then(|v| v.as_array()); - - let attr_names = match (name, names) { - (Some(name), None) => vec![_normalize_attr_name(name.try_as_str()?)], - (None, Some(names)) => names - .iter() - .map(|v| v.try_as_str().map(_normalize_attr_name)) - .collect::>()?, - _ => Err(AriesVcxCoreError::from_msg( - AriesVcxCoreErrorKind::InvalidInput, - "exactly one of 'name' or 'names' must be present", - ))?, + let (names, non_revoked, restrictions) = match requested_attributes.get(&reft) { + Some(attribute_info) => { + let attr_names = match ( + attribute_info.name.to_owned(), + attribute_info.names.to_owned(), + ) { + (Some(name), None) => vec![_normalize_attr_name(&name)], + (None, Some(names)) => names + .iter() + .map(String::as_str) + .map(_normalize_attr_name) + .collect::>(), + _ => Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::InvalidInput, + "exactly one of 'name' or 'names' must be present", + ))?, + }; + ( + attr_names, + attribute_info.non_revoked.to_owned(), + attribute_info.restrictions.to_owned(), + ) + } + None => match requested_predicates.get(&reft) { + Some(requested_val) => ( + vec![requested_val.name.to_owned()], + requested_val.non_revoked.to_owned(), + requested_val.restrictions.to_owned(), + ), + None => Err(AriesVcxCoreError::from_msg( + AriesVcxCoreErrorKind::InvalidProofRequest, + "Requested attribute or predicate not found in proof request", + ))?, + }, }; - let non_revoked = requested_val.get("non_revoked"); // note that aca-py askar fetches from proof_req json - let restrictions = requested_val.get("restrictions"); - let credx_creds = self - ._get_credentials_for_proof_req_for_attr_name(wallet, restrictions, attr_names) + ._get_credentials_for_proof_req_for_attr_name( + wallet, + restrictions.map(serde_json::to_value).transpose()?, + names, + ) .await?; let mut credentials_json = vec![]; for (cred_id, credx_cred) in credx_creds { - credentials_json.push(json!({ - "cred_info": _make_cred_info(&cred_id, &credx_cred)?, - "interval": non_revoked - })) + credentials_json.push(RetrievedCredentialForReferent { + cred_info: _make_cred_info(&cred_id, &credx_cred)?, + interval: non_revoked.clone(), + }); } - cred_by_attr[ATTRS][reft] = Value::Array(credentials_json); + cred_by_attr + .credentials_by_referent + .insert(reft, credentials_json); } - Ok(serde_json::from_value(cred_by_attr)?) + Ok(cred_by_attr) } async fn prover_create_credential_req( @@ -1121,7 +1080,7 @@ impl BaseAnonCreds for Anoncreds { } for (raw_attr_name, attr_value) in credential.values.0.iter() { - let attr_name = _normalize_attr_name(raw_attr_name); + let attr_name = _normalize_attr_name(raw_attr_name.as_str()); // add attribute name and raw value pair let value_tag_name = _format_attribute_as_value_tag_name(&attr_name); tags[value_tag_name] = Value::String(attr_value.raw.to_string()); @@ -1337,12 +1296,9 @@ impl BaseAnonCreds for Anoncreds { fn get_rev_state( cred_id: &str, credential: &Credential, - detail: &Value, + timestamp: Option, rev_states: Option<&RevocationStatesMap>, ) -> VcxCoreResult<(Option, Option)> { - let timestamp = detail - .get("timestamp") - .and_then(|timestamp| timestamp.as_u64()); let cred_rev_reg_id = credential.rev_reg_id.as_ref().map(|id| id.0.to_string()); let rev_state = if let (Some(timestamp), Some(cred_rev_reg_id)) = (timestamp, cred_rev_reg_id) { let rev_state = rev_states diff --git a/aries/aries_vcx_core/src/anoncreds/base_anoncreds.rs b/aries/aries_vcx_core/src/anoncreds/base_anoncreds.rs index 51e284f2c1..acfe1a84d9 100644 --- a/aries/aries_vcx_core/src/anoncreds/base_anoncreds.rs +++ b/aries/aries_vcx_core/src/anoncreds/base_anoncreds.rs @@ -20,7 +20,7 @@ use anoncreds_types::data_types::{ credential::{Credential, CredentialValues}, nonce::Nonce, pres_request::PresentationRequest, - presentation::Presentation, + presentation::{Presentation, RequestedCredentials}, revocation_state::CredentialRevocationState, }, }; @@ -99,7 +99,7 @@ pub trait BaseAnonCreds: std::fmt::Debug + Send + Sync { &self, wallet: &impl BaseWallet, proof_req_json: PresentationRequest, - requested_credentials_json: &str, + requested_credentials_json: RequestedCredentials, link_secret_id: &LinkSecretId, schemas_json: SchemasMap, credential_defs_json: CredentialDefinitionsMap, diff --git a/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs b/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs index b249207739..76ce3fbfd7 100644 --- a/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs +++ b/aries/aries_vcx_core/src/anoncreds/credx_anoncreds/mod.rs @@ -27,7 +27,7 @@ use anoncreds_types::data_types::{ credential::{Credential, CredentialValues}, nonce::Nonce, pres_request::PresentationRequest, - presentation::Presentation, + presentation::{Presentation, RequestedCredentials}, revocation_state::CredentialRevocationState, }, }; @@ -63,10 +63,7 @@ use super::base_anoncreds::{ }; use crate::{ errors::error::{AriesVcxCoreError, AriesVcxCoreErrorKind, VcxCoreResult}, - utils::{ - constants::ATTRS, - json::{AsTypeOrDeserializationError, TryGetIndex}, - }, + utils::{constants::ATTRS, json::AsTypeOrDeserializationError}, wallet::{ base_wallet::{ record::Record, record_category::RecordCategory, search_filter::SearchFilter, @@ -648,18 +645,11 @@ impl BaseAnonCreds for IndyCredxAnonCreds { Ok((cred.convert(())?, cred_rev_id)) } - /// * `requested_credentials_json`: either a credential or self-attested attribute for each - /// requested attribute { "self_attested_attributes": { "self_attested_attribute_referent": - /// string }, "requested_attributes": { "requested_attribute_referent_1": {"cred_id": string, - /// "timestamp": Optional, revealed: }}, "requested_attribute_referent_2": - /// {"cred_id": string, "timestamp": Optional, revealed: }} }, - /// "requested_predicates": { "requested_predicates_referent_1": {"cred_id": string, - /// "timestamp": Optional }}, } } async fn prover_create_proof( &self, wallet: &impl BaseWallet, proof_req_json: PresentationRequest, - requested_credentials_json: &str, + requested_credentials_json: RequestedCredentials, link_secret_id: &LinkSecretId, schemas_json: SchemasMap, credential_defs_json: CredentialDefinitionsMap, @@ -667,11 +657,9 @@ impl BaseAnonCreds for IndyCredxAnonCreds { ) -> VcxCoreResult { let pres_req: CredxPresentationRequest = proof_req_json.convert(())?; - let requested_credentials: Value = serde_json::from_str(requested_credentials_json)?; - let requested_attributes = (&requested_credentials).try_get("requested_attributes")?; - - let requested_predicates = (&requested_credentials).try_get("requested_predicates")?; - let self_attested_attributes = requested_credentials.get("self_attested_attributes"); + let requested_attributes = requested_credentials_json.requested_attributes; + let requested_predicates = requested_credentials_json.requested_predicates; + let self_attested_attributes = requested_credentials_json.self_attested_attributes; let schemas: HashMap = schemas_json.convert(())?; @@ -689,11 +677,9 @@ impl BaseAnonCreds for IndyCredxAnonCreds { > = HashMap::new(); // add cred data and referent details for each requested attribute - for (reft, detail) in requested_attributes.try_as_object()?.iter() { - let _cred_id = detail.try_get("cred_id")?; - let cred_id = _cred_id.try_as_str()?; - - let revealed = detail.try_get("revealed")?.try_as_bool()?; + for (reft, detail) in requested_attributes { + let cred_id = &detail.cred_id; + let revealed = detail.revealed; if let Some((_, _, _, req_attr_refts_revealed, _)) = proof_details_by_cred_id.get_mut(cred_id) @@ -703,8 +689,12 @@ impl BaseAnonCreds for IndyCredxAnonCreds { } else { let credential = Self::_get_credential(wallet, cred_id).await?; - let (timestamp, rev_state) = - get_rev_state(cred_id, &credential, detail, revoc_states_json.as_ref())?; + let (timestamp, rev_state) = get_rev_state( + cred_id, + &credential, + detail.timestamp, + revoc_states_json.as_ref(), + )?; proof_details_by_cred_id.insert( cred_id.to_string(), @@ -720,9 +710,8 @@ impl BaseAnonCreds for IndyCredxAnonCreds { } // add cred data and referent details for each requested predicate - for (reft, detail) in requested_predicates.try_as_object()?.iter() { - let _cred_id = detail.try_get("cred_id")?; - let cred_id = _cred_id.try_as_str()?; + for (reft, detail) in requested_predicates { + let cred_id = &detail.cred_id; if let Some((_, _, _, _, req_preds_refts)) = proof_details_by_cred_id.get_mut(cred_id) { // mapping made for this credential already, add reft @@ -730,8 +719,12 @@ impl BaseAnonCreds for IndyCredxAnonCreds { } else { let credential = Self::_get_credential(wallet, cred_id).await?; - let (timestamp, rev_state) = - get_rev_state(cred_id, &credential, detail, revoc_states_json.as_ref())?; + let (timestamp, rev_state) = get_rev_state( + cred_id, + &credential, + detail.timestamp, + revoc_states_json.as_ref(), + )?; proof_details_by_cred_id.insert( cred_id.to_string(), @@ -765,30 +758,12 @@ impl BaseAnonCreds for IndyCredxAnonCreds { } } - // create self_attested by iterating thru self_attested_value - let self_attested = if let Some(self_attested_value) = self_attested_attributes { - let mut self_attested_map: HashMap = HashMap::new(); - let self_attested_obj = self_attested_value.try_as_object()?.clone(); - let self_attested_iter = self_attested_obj.iter(); - for (k, v) in self_attested_iter { - self_attested_map.insert(k.to_string(), v.try_as_str()?.to_string()); - } - - if self_attested_map.is_empty() { - None - } else { - Some(self_attested_map) - } - } else { - None - }; - let link_secret = Self::get_link_secret(wallet, link_secret_id).await?; let presentation = credx::prover::create_presentation( &pres_req, present_credentials, - self_attested, + Some(self_attested_attributes), &link_secret, &hashmap_as_ref(&schemas), &hashmap_as_ref(&credential_defs_json.convert(())?), @@ -1311,12 +1286,9 @@ impl BaseAnonCreds for IndyCredxAnonCreds { fn get_rev_state( cred_id: &str, credential: &CredxCredential, - detail: &Value, + timestamp: Option, rev_states: Option<&RevocationStatesMap>, ) -> VcxCoreResult<(Option, Option)> { - let timestamp = detail - .get("timestamp") - .and_then(|timestamp| timestamp.as_u64()); let cred_rev_reg_id = credential.rev_reg_id.as_ref().map(|id| id.0.to_string()); let rev_state = if let (Some(timestamp), Some(cred_rev_reg_id)) = (timestamp, cred_rev_reg_id) { let rev_state = rev_states diff --git a/aries/misc/anoncreds_types/src/data_types/messages/cred_selection.rs b/aries/misc/anoncreds_types/src/data_types/messages/cred_selection.rs index a0417482ad..92a162db32 100644 --- a/aries/misc/anoncreds_types/src/data_types/messages/cred_selection.rs +++ b/aries/misc/anoncreds_types/src/data_types/messages/cred_selection.rs @@ -5,7 +5,7 @@ use crate::data_types::identifiers::{cred_def_id::CredentialDefinitionId, schema /// Data structure representing the credentials in the wallet, which are suitable /// for presentation against a proof request. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] pub struct RetrievedCredentials { /// A map of the proof request's requested referents (predicates and attribute referents) /// against a list of [RetrievedCredentialForReferent] items which represent credentials diff --git a/aries/misc/anoncreds_types/src/data_types/messages/presentation.rs b/aries/misc/anoncreds_types/src/data_types/messages/presentation.rs index 21b90ccf3b..8e561b8d3a 100644 --- a/aries/misc/anoncreds_types/src/data_types/messages/presentation.rs +++ b/aries/misc/anoncreds_types/src/data_types/messages/presentation.rs @@ -77,6 +77,26 @@ impl Validatable for Presentation { } } +#[derive(Serialize, Deserialize, Debug)] +pub struct RequestedAttribute { + pub cred_id: String, + pub timestamp: Option, + pub revealed: bool, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct RequestedPredicate { + pub cred_id: String, + pub timestamp: Option, +} + +#[derive(Default, Serialize, Deserialize, Debug)] +pub struct RequestedCredentials { + pub self_attested_attributes: HashMap, + pub requested_attributes: HashMap, + pub requested_predicates: HashMap, +} + #[cfg(test)] mod tests { use super::*; diff --git a/aries/misc/test_utils/src/mockdata/mock_anoncreds.rs b/aries/misc/test_utils/src/mockdata/mock_anoncreds.rs index 92a56fe2a3..33d325908e 100644 --- a/aries/misc/test_utils/src/mockdata/mock_anoncreds.rs +++ b/aries/misc/test_utils/src/mockdata/mock_anoncreds.rs @@ -20,7 +20,7 @@ use anoncreds_types::data_types::{ credential::{Credential, CredentialValues}, nonce::Nonce, pres_request::PresentationRequest, - presentation::Presentation, + presentation::{Presentation, RequestedCredentials}, revocation_state::CredentialRevocationState, }, }; @@ -121,7 +121,7 @@ impl BaseAnonCreds for MockAnoncreds { &self, __wallet: &impl BaseWallet, _proof_req_json: PresentationRequest, - _requested_credentials_json: &str, + _requested_credentials_json: RequestedCredentials, _link_secret_id: &LinkSecretId, _schemas_json: SchemasMap, _credential_defs_json: CredentialDefinitionsMap, diff --git a/justfile b/justfile index ea64c46356..4ad11bec80 100644 --- a/justfile +++ b/justfile @@ -41,7 +41,7 @@ test-integration-aries-vcx test_name="": cargo test --manifest-path="aries/aries_vcx/Cargo.toml" -F vdrtools_wallet,credx -- --ignored {{test_name}} test-integration-aries-vcx-anoncreds-rs test_name="": - cargo test --manifest-path="aries/aries_vcx/Cargo.toml" -F anoncreds --test test_revocations --test test_proof_presentation --test test_anoncreds -- --ignored {{test_name}} + cargo test --manifest-path="aries/aries_vcx/Cargo.toml" -F anoncreds --test test_revocations --test test_proof_presentation --test test_anoncreds --test test_verifier -- --ignored {{test_name}} test-integration-aries-vcx-mysql test_name="": cargo test --manifest-path="aries/aries_vcx/Cargo.toml" test_mysql -- --include-ignored {{test_name}}