diff --git a/src/data_types/pres_request.rs b/src/data_types/pres_request.rs index 7ae4ed48..a4aef6e8 100644 --- a/src/data_types/pres_request.rs +++ b/src/data_types/pres_request.rs @@ -22,7 +22,7 @@ pub struct PresentationRequestPayload { pub requested_attributes: HashMap, #[serde(default)] pub requested_predicates: HashMap, - pub non_revoked: Option, + pub non_revoked: Option, } #[derive(Debug, PartialEq, Eq)] @@ -123,18 +123,18 @@ impl Serialize for PresentationRequest { pub type PresentationRequestExtraQuery = HashMap; #[derive(Clone, Default, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] -pub struct NonRevocedInterval { +pub struct NonRevokedInterval { pub from: Option, pub to: Option, } -impl NonRevocedInterval { +impl NonRevokedInterval { pub fn new(from: Option, to: Option) -> Self { Self { from, to } } // Returns the most stringent interval, // i.e. the latest from and the earliest to - pub fn compare_and_set(&mut self, to_compare: &NonRevocedInterval) { + pub fn compare_and_set(&mut self, to_compare: &NonRevokedInterval) { // Update if // - the new `from` value is later, smaller interval // - the new `from` value is Some if previouly was None @@ -185,7 +185,7 @@ pub struct AttributeInfo { #[serde(skip_serializing_if = "Option::is_none")] pub names: Option>, pub restrictions: Option, - pub non_revoked: Option, + pub non_revoked: Option, } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] @@ -194,7 +194,7 @@ pub struct PredicateInfo { pub p_type: PredicateTypes, pub p_value: i32, pub restrictions: Option, - pub non_revoked: Option, + pub non_revoked: Option, } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] @@ -383,7 +383,7 @@ mod tests { #[test] fn override_works() { - let mut interval = NonRevocedInterval::default(); + let mut interval = NonRevokedInterval::default(); let override_map = HashMap::from([(10u64, 5u64)]); interval.from = Some(10); @@ -393,10 +393,10 @@ mod tests { #[test] fn compare_and_set_works() { - let mut int = NonRevocedInterval::default(); - let wide_int = NonRevocedInterval::new(Some(1), Some(100)); - let mid_int = NonRevocedInterval::new(Some(5), Some(80)); - let narrow_int = NonRevocedInterval::new(Some(10), Some(50)); + let mut int = NonRevokedInterval::default(); + let wide_int = NonRevokedInterval::new(Some(1), Some(100)); + let mid_int = NonRevokedInterval::new(Some(5), Some(80)); + let narrow_int = NonRevokedInterval::new(Some(10), Some(50)); assert_eq!(int.from, None); assert_eq!(int.to, None); diff --git a/src/ffi/presentation.rs b/src/ffi/presentation.rs index c56c1d86..8a95b8ec 100644 --- a/src/ffi/presentation.rs +++ b/src/ffi/presentation.rs @@ -218,24 +218,24 @@ pub extern "C" fn anoncreds_create_presentation( pub struct FfiNonrevokedIntervalOverride<'a> { rev_reg_def_id: FfiStr<'a>, /// Timestamp in the `PresentationRequest` - req_timestamp: i64, + requested_from_ts: i64, /// Timestamp from which verifier accepts, /// should be less than `req_timestamp` - override_timestamp: i64, + override_rev_status_list_ts: i64, } impl<'a> FfiNonrevokedIntervalOverride<'a> { fn load(&self) -> Result<(RevocationRegistryDefinitionId, u64, u64)> { let id = RevocationRegistryDefinitionId::new(self.rev_reg_def_id.as_str().to_owned())?; - let req_timestamp = self - .req_timestamp + let requested_from_ts = self + .requested_from_ts .try_into() .map_err(|_| err_msg!("Invalid req timestamp "))?; - let override_timestamp = self - .override_timestamp + let override_rev_status_list_ts = self + .override_rev_status_list_ts .try_into() .map_err(|_| err_msg!("Invalid override timestamp "))?; - Ok((id, req_timestamp, override_timestamp)) + Ok((id, requested_from_ts, override_rev_status_list_ts)) } } diff --git a/src/services/helpers.rs b/src/services/helpers.rs index 2f14ed78..02326021 100644 --- a/src/services/helpers.rs +++ b/src/services/helpers.rs @@ -3,7 +3,8 @@ use std::collections::{HashMap, HashSet}; use crate::data_types::{ credential::AttributeValues, nonce::Nonce, - pres_request::{AttributeInfo, PredicateInfo}, + pres_request::{AttributeInfo, NonRevokedInterval, PredicateInfo, PresentationRequestPayload}, + presentation::RequestedProof, }; use crate::utils::hash::SHA256; @@ -137,3 +138,105 @@ pub fn build_sub_proof_request( pub fn new_nonce() -> Result { Nonce::new().map_err(err_map!(Unexpected)) } + +pub fn get_revealed_attributes_for_credential( + sub_proof_index: usize, + requested_proof: &RequestedProof, + pres_req: &PresentationRequestPayload, +) -> Result<(Vec, Option)> { + trace!("_get_revealed_attributes_for_credential >>> sub_proof_index: {:?}, requested_credentials: {:?}, pres_req: {:?}", + sub_proof_index, requested_proof, pres_req); + let mut nonrevoked_interval: Option = None; + let mut revealed_attrs_for_credential = requested_proof + .revealed_attrs + .iter() + .filter(|&(attr_referent, revealed_attr_info)| { + sub_proof_index == revealed_attr_info.sub_proof_index as usize + && pres_req.requested_attributes.contains_key(attr_referent) + }) + .map(|(attr_referent, _)| { + let info = pres_req.requested_attributes[attr_referent].clone(); + if let Some(int) = &info.non_revoked { + match nonrevoked_interval.as_mut() { + Some(ni) => { + ni.compare_and_set(int); + } + None => nonrevoked_interval = Some(int.clone()), + } + }; + + info + }) + .collect::>(); + + revealed_attrs_for_credential.append( + &mut requested_proof + .revealed_attr_groups + .iter() + .filter(|&(attr_referent, revealed_attr_info)| { + sub_proof_index == revealed_attr_info.sub_proof_index as usize + && pres_req.requested_attributes.contains_key(attr_referent) + }) + .map(|(attr_referent, _)| { + let info = pres_req.requested_attributes[attr_referent].clone(); + if let Some(int) = &info.non_revoked { + match nonrevoked_interval.as_mut() { + Some(ni) => { + ni.compare_and_set(int); + } + None => nonrevoked_interval = Some(NonRevokedInterval::default()), + } + }; + info + }) + .collect::>(), + ); + + trace!( + "_get_revealed_attributes_for_credential <<< revealed_attrs_for_credential: {:?}", + revealed_attrs_for_credential + ); + + Ok((revealed_attrs_for_credential, nonrevoked_interval)) +} + +pub fn get_predicates_for_credential( + sub_proof_index: usize, + requested_proof: &RequestedProof, + pres_req: &PresentationRequestPayload, +) -> Result<(Vec, Option)> { + trace!("_get_predicates_for_credential >>> sub_proof_index: {:?}, requested_credentials: {:?}, pres_req: {:?}", + sub_proof_index, requested_proof, pres_req); + + let mut nonrevoked_interval: Option = None; + let predicates_for_credential = requested_proof + .predicates + .iter() + .filter(|&(predicate_referent, requested_referent)| { + sub_proof_index == requested_referent.sub_proof_index as usize + && pres_req + .requested_predicates + .contains_key(predicate_referent) + }) + .map(|(predicate_referent, _)| { + let info = pres_req.requested_predicates[predicate_referent].clone(); + if let Some(int) = &info.non_revoked { + match nonrevoked_interval.as_mut() { + Some(ni) => { + ni.compare_and_set(int); + } + None => nonrevoked_interval = Some(int.clone()), + } + }; + + info + }) + .collect::>(); + + trace!( + "_get_predicates_for_credential <<< predicates_for_credential: {:?}", + predicates_for_credential + ); + + Ok((predicates_for_credential, nonrevoked_interval)) +} diff --git a/src/services/prover.rs b/src/services/prover.rs index 9caafd9e..717bb079 100644 --- a/src/services/prover.rs +++ b/src/services/prover.rs @@ -203,6 +203,52 @@ pub fn create_presentation( )?; let sub_proof_request = build_sub_proof_request(&req_attrs, &req_predicates)?; + update_requested_proof( + req_attrs, + req_predicates, + pres_req_val, + credential, + sub_proof_index, + &mut requested_proof, + )?; + + // Checks conditions to add revocation proof + let (rev_reg, witness) = if pres_req_val.non_revoked.is_some() { + // Global revocation request + ( + present.rev_state.as_ref().map(|r_info| &r_info.rev_reg), + present.rev_state.as_ref().map(|r_info| &r_info.witness), + ) + } else { + // There exists at least 1 local revocation request + let ((_, nonrevoked_attr), (_, nonrevoked_preds)) = ( + get_revealed_attributes_for_credential( + sub_proof_index as usize, + &requested_proof, + pres_req_val, + )?, + get_predicates_for_credential( + sub_proof_index as usize, + &requested_proof, + pres_req_val, + )?, + ); + if nonrevoked_attr.is_some() || nonrevoked_preds.is_some() { + ( + present.rev_state.as_ref().map(|r_info| &r_info.rev_reg), + present.rev_state.as_ref().map(|r_info| &r_info.witness), + ) + } else { + // Neither global nor local is required + (None, None) + } + }; + + // if `present.rev_state` is available, + // then it will create an init_proof that contains NRP. + // + // Therefore, this will have to be part of the finalised `aggregated_proof`. + // Regardless if nonrevoke_interval is requested by the verifier proof_builder.add_sub_proof_request( &sub_proof_request, &credential_schema, @@ -210,8 +256,8 @@ pub fn create_presentation( &credential.signature, &credential_values, &credential_pub_key, - present.rev_state.as_ref().map(|r_info| &r_info.rev_reg), - present.rev_state.as_ref().map(|r_info| &r_info.witness), + rev_reg, + witness, )?; let identifier = match pres_req { @@ -231,15 +277,6 @@ pub fn create_presentation( identifiers.push(identifier); - update_requested_proof( - req_attrs, - req_predicates, - pres_req_val, - credential, - sub_proof_index, - &mut requested_proof, - )?; - sub_proof_index += 1; } diff --git a/src/services/verifier.rs b/src/services/verifier.rs index 6ddd1adf..38388874 100644 --- a/src/services/verifier.rs +++ b/src/services/verifier.rs @@ -13,7 +13,7 @@ use crate::data_types::schema::Schema; use crate::data_types::schema::SchemaId; use crate::data_types::{ nonce::Nonce, - pres_request::{AttributeInfo, NonRevocedInterval, PredicateInfo, PresentationRequestPayload}, + pres_request::{AttributeInfo, NonRevokedInterval, PresentationRequestPayload}, presentation::{Identifier, RequestedProof, RevealedAttributeInfo}, }; use crate::error::Result; @@ -71,10 +71,10 @@ pub fn verify_presentation( &received_predicates, )?; - // This ensures the encoded values are same as request + // Ensures the encoded values are same as request verify_revealed_attribute_values(pres_req, presentation)?; - // This does not verify non-revoked requirements + // Ensures the restrictinos set out in the request is met verify_requested_restrictions( pres_req, schemas, @@ -147,28 +147,35 @@ pub fn verify_presentation( // Collaspe to the most stringent local interval for the attributes / predicates, // we can do this because there is only 1 revocation status list for this credential // if it satsifies the most stringent interval, it will satisfy all intervals - let mut cred_nonrevoked_interval = attrs_nonrevoked_interval; - cred_nonrevoked_interval.compare_and_set(&pred_nonrevoked_interval); + let mut cred_nonrevoked_interval: Option = + match (attrs_nonrevoked_interval, pred_nonrevoked_interval) { + (Some(attr), None) => Some(attr), + (None, Some(pred)) => Some(pred), + (Some(mut attr), Some(pred)) => { + attr.compare_and_set(&pred); + Some(attr) + } + _ => None, + }; // Global interval is override by the local one, // we only need to update if local is None and Global is Some, // do not need to update if global is more stringent - if let (Some(interval), None, None) = ( - pres_req.non_revoked.as_ref(), - cred_nonrevoked_interval.from, - cred_nonrevoked_interval.to, + if let (Some(global), None) = ( + pres_req.non_revoked.clone(), + cred_nonrevoked_interval.as_mut(), ) { - cred_nonrevoked_interval.compare_and_set(interval); + cred_nonrevoked_interval = Some(global); }; // Revocation checks is required iff both conditions are met: - // - Credential is revokable (cred_defs is input by the verifier, trustable) + // - Credential is revokable (input from verifier, trustable) // - PresentationReq has asked for NRP* (input from verifier, trustable) // // * This is done by setting a NonRevokedInterval either for attr / predicate / global let (rev_reg_def, rev_reg) = if let (Some(_), true) = ( cred_def.value.revocation.as_ref(), - cred_nonrevoked_interval.from.is_some() || cred_nonrevoked_interval.to.is_some(), + cred_nonrevoked_interval.is_some(), ) { let timestamp = identifier .timestamp @@ -195,11 +202,17 @@ pub fn verify_presentation( // Override Interval if an earlier `from` value is accepted by the verifier nonrevoke_interval_override.map(|maps| { - maps.get(&rev_reg_def_id) - .map(|map| cred_nonrevoked_interval.update_with_override(map)) + maps.get(&rev_reg_def_id).map(|map| { + cred_nonrevoked_interval + .as_mut() + .map(|int| int.update_with_override(map)) + }) }); - cred_nonrevoked_interval.is_valid(timestamp)?; + // Validate timestamp + cred_nonrevoked_interval + .map(|int| int.is_valid(timestamp)) + .transpose()?; let rev_reg_def = Some( rev_reg_defs @@ -266,92 +279,6 @@ pub fn generate_nonce() -> Result { new_nonce() } -fn get_revealed_attributes_for_credential( - sub_proof_index: usize, - requested_proof: &RequestedProof, - pres_req: &PresentationRequestPayload, -) -> Result<(Vec, NonRevocedInterval)> { - trace!("_get_revealed_attributes_for_credential >>> sub_proof_index: {:?}, requested_credentials: {:?}, pres_req: {:?}", - sub_proof_index, requested_proof, pres_req); - - let mut nonrevoked_interval = NonRevocedInterval::default(); - let mut revealed_attrs_for_credential = requested_proof - .revealed_attrs - .iter() - .filter(|&(attr_referent, revealed_attr_info)| { - sub_proof_index == revealed_attr_info.sub_proof_index as usize - && pres_req.requested_attributes.contains_key(attr_referent) - }) - .map(|(attr_referent, _)| { - let info = pres_req.requested_attributes[attr_referent].clone(); - if info.non_revoked.is_some() { - nonrevoked_interval.compare_and_set(info.non_revoked.as_ref().unwrap()); - } - info - }) - .collect::>(); - - revealed_attrs_for_credential.append( - &mut requested_proof - .revealed_attr_groups - .iter() - .filter(|&(attr_referent, revealed_attr_info)| { - sub_proof_index == revealed_attr_info.sub_proof_index as usize - && pres_req.requested_attributes.contains_key(attr_referent) - }) - .map(|(attr_referent, _)| { - let info = pres_req.requested_attributes[attr_referent].clone(); - if info.non_revoked.is_some() { - nonrevoked_interval.compare_and_set(info.non_revoked.as_ref().unwrap()); - } - info - }) - .collect::>(), - ); - - trace!( - "_get_revealed_attributes_for_credential <<< revealed_attrs_for_credential: {:?}", - revealed_attrs_for_credential - ); - - Ok((revealed_attrs_for_credential, nonrevoked_interval)) -} - -fn get_predicates_for_credential( - sub_proof_index: usize, - requested_proof: &RequestedProof, - pres_req: &PresentationRequestPayload, -) -> Result<(Vec, NonRevocedInterval)> { - trace!("_get_predicates_for_credential >>> sub_proof_index: {:?}, requested_credentials: {:?}, pres_req: {:?}", - sub_proof_index, requested_proof, pres_req); - - let mut nonrevoked_interval = NonRevocedInterval::default(); - let predicates_for_credential = requested_proof - .predicates - .iter() - .filter(|&(predicate_referent, requested_referent)| { - sub_proof_index == requested_referent.sub_proof_index as usize - && pres_req - .requested_predicates - .contains_key(predicate_referent) - }) - .map(|(predicate_referent, _)| { - let info = pres_req.requested_predicates[predicate_referent].clone(); - if info.non_revoked.is_some() { - nonrevoked_interval.compare_and_set(info.non_revoked.as_ref().unwrap()); - } - info - }) - .collect::>(); - - trace!( - "_get_predicates_for_credential <<< predicates_for_credential: {:?}", - predicates_for_credential - ); - - Ok((predicates_for_credential, nonrevoked_interval)) -} - fn compare_attr_from_proof_and_request( pres_req: &PresentationRequestPayload, received_revealed_attrs: &HashMap, diff --git a/tests/multiple-credentials.rs b/tests/multiple-credentials.rs index 46ef5b43..431d94db 100644 --- a/tests/multiple-credentials.rs +++ b/tests/multiple-credentials.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use anoncreds::{ data_types::{ - pres_request::{NonRevocedInterval, PresentationRequestPayload}, + pres_request::{NonRevokedInterval, PresentationRequestPayload}, + rev_reg_def::RevocationRegistryDefinitionId, schema::SchemaId, }, types::PresentationRequest, @@ -25,9 +26,8 @@ const GLOBAL_FROM: u64 = 5; const GLOBAL_TO: u64 = 25; const LOCAL_FROM: u64 = 10; const OVERRIDE_LOCAL_FROM: u64 = 8; -const LOCAL_TO: u32 = 20; -const TS_WITHIN_LOCAL_OVERRIDE: u32 = 9; -const TS_WITHIN_GLOBAL_ONLY: u32 = 7; +const LOCAL_TO: u64 = 20; +const TS_WITHIN_LOCAL_OVERRIDE: u64 = 9; const SCHEMA_ID_1: &str = "mock:uri:schema1"; const SCHEMA_ID_2: &str = "mock:uri:schema2"; @@ -38,23 +38,16 @@ static CRED_DEF_ID_2: &'static str = "mock:uri:2"; static REV_REG_ID_1: &'static str = "mock:uri:revregid1"; static REV_REG_ID_2: &'static str = "mock:uri:revregid2"; -// This returns Presentation Requests with following nonrevoked intervals -// [0]: Global -// [1]: Local for attributes belonging to both credentials -// [2]: Global and Local, where local is more stringent -fn test_2_different_revoke_reqs() -> Vec { - let nonce_1 = verifier::generate_nonce().expect("Error generating presentation request nonce"); - let nonce_2 = verifier::generate_nonce().expect("Error generating presentation request nonce"); - let nonce_3 = verifier::generate_nonce().expect("Error generating presentation request nonce"); - +fn create_request(input: &ReqInput) -> PresentationRequest { + let nonce = verifier::generate_nonce().unwrap(); let json = json!({ - "nonce": nonce_1, - "name":"pres_req_1", + "nonce": nonce, + "name":input.req_name , "version":"0.1", "requested_attributes":{ "attr1_referent":{ "name":"name", - "issuer_id": ISSUER_ID + "issuer_id": input.issuer, }, "attr2_referent":{ "name":"sex" @@ -71,32 +64,21 @@ fn test_2_different_revoke_reqs() -> Vec { }, }); - let mut p1: PresentationRequestPayload = serde_json::from_value(json.clone()).unwrap(); - let mut p2: PresentationRequestPayload = serde_json::from_value(json.clone()).unwrap(); - let mut p3: PresentationRequestPayload = serde_json::from_value(json).unwrap(); - - // Global non_revoked - p1.non_revoked = Some(NonRevocedInterval::new(Some(5), Some(25))); - p1.nonce = nonce_1; - p2.nonce = nonce_2; - p3.nonce = nonce_3; - - // Local non_revoked - if let Some(at1) = p2.requested_attributes.get_mut("attr4_referent") { - at1.non_revoked = Some(NonRevocedInterval::new(Some(10), Some(20))); - } else { - panic!("Cannot add non_revoke to attri"); + let mut presentation: PresentationRequestPayload = serde_json::from_value(json).unwrap(); + presentation.non_revoked = input.global_nonrevoke.clone(); + + for ni in input.attr_nonrevoke.iter() { + let at = presentation.requested_attributes.get_mut(ni.0).unwrap(); + at.non_revoked = Some(ni.1.clone()); } - if let Some(at2) = p2.requested_attributes.get_mut("attr5_referent") { - at2.non_revoked = Some(NonRevocedInterval::new(Some(10), Some(20))); - } else { - panic!("Cannot add non_revoke to attri"); + + for ni in input.pred_nonrevoke.iter() { + let at = presentation.requested_predicates.get_mut(ni.0).unwrap(); + at.non_revoked = Some(ni.1.clone()); } - vec![ - PresentationRequest::PresentationRequestV1(p1), - PresentationRequest::PresentationRequestV1(p2), - ] + log::info!("\n Request: {:?}", presentation); + PresentationRequest::PresentationRequestV1(presentation) } fn create_issuer_data<'a>() -> utils::IssuerValues<'a> { @@ -138,8 +120,78 @@ fn create_issuer_data<'a>() -> utils::IssuerValues<'a> { issuer1_creds } +pub struct ReqInput<'a> { + pub req_name: &'a str, + pub issuer: &'a str, + pub global_nonrevoke: Option, + pub attr_nonrevoke: Vec<(&'a str, NonRevokedInterval)>, + pub pred_nonrevoke: Vec<(&'a str, NonRevokedInterval)>, +} + +fn test_requests_generate<'a>() -> Vec> { + let r0 = ReqInput { + req_name: "global_rev", + issuer: ISSUER_ID, + global_nonrevoke: Some(NonRevokedInterval::new(Some(GLOBAL_FROM), Some(GLOBAL_TO))), + attr_nonrevoke: vec![], + pred_nonrevoke: vec![], + }; + let r1 = ReqInput { + req_name: "local_rev", + issuer: ISSUER_ID, + global_nonrevoke: None, + attr_nonrevoke: vec![ + ( + "attr2_referent", + NonRevokedInterval::new(Some(LOCAL_FROM), Some(LOCAL_TO)), + ), + ( + "attr5_referent", + NonRevokedInterval::new(Some(LOCAL_FROM), Some(LOCAL_TO)), + ), + ], + pred_nonrevoke: vec![], + }; + let r2 = ReqInput { + req_name: "both_rev_attr", + issuer: ISSUER_ID, + global_nonrevoke: Some(NonRevokedInterval::new(Some(GLOBAL_FROM), Some(GLOBAL_TO))), + attr_nonrevoke: vec![ + ( + "attr2_referent", + NonRevokedInterval::new(Some(LOCAL_FROM), Some(LOCAL_TO)), + ), + ( + "attr5_referent", + NonRevokedInterval::new(Some(LOCAL_FROM), Some(LOCAL_TO)), + ), + ], + pred_nonrevoke: vec![], + }; + let r3 = ReqInput { + req_name: "both_rev_pred", + issuer: ISSUER_ID, + global_nonrevoke: Some(NonRevokedInterval::new(Some(GLOBAL_FROM), Some(GLOBAL_TO))), + attr_nonrevoke: vec![], + pred_nonrevoke: vec![( + "predicate1_referent", + NonRevokedInterval::new(Some(LOCAL_FROM), Some(LOCAL_TO)), + )], + }; + let r4 = ReqInput { + req_name: "no_rev", + issuer: ISSUER_ID, + global_nonrevoke: None, + attr_nonrevoke: vec![], + pred_nonrevoke: vec![], + }; + + vec![r0, r1, r2, r3, r4] +} + #[test] fn anoncreds_with_multiple_credentials_per_request() { + env_logger::init(); let mut mock = utils::Mock::new(&[ISSUER_ID], &[PROVER_ID], TF_PATH, MAX_CRED_NUM); let issuer1_creds = create_issuer_data(); @@ -159,14 +211,19 @@ fn anoncreds_with_multiple_credentials_per_request() { // These are within interval let time_initial_rev_reg = 8u64; - let time_after_credential = 10u64; + let time_after_credential = TS_WITHIN_LOCAL_OVERRIDE; let issuance_by_default = true; - // To test: - // pres_request_1: global interval; Tests verification for revocable credentials only - // pres_request_2: local intervals for both credential; Tests verification for revocable credentials only - // Verifier creates a presentation request for each - let reqs = test_2_different_revoke_reqs(); + // This returns Presentation Requests with following nonrevoked intervals + // [0]: Global + // [1]: Local for attributes belonging to both credentials + // [2]: Global and Local attributes , where local is more stringent + // [3]: Global and Local predeicate, where local is more stringent + // [4]: no NRP required + let reqs: Vec = test_requests_generate() + .iter() + .map(|x| create_request(&x)) + .collect(); // 1: Issuer setup (credate cred defs, rev defs(optional), cred_offers) mock.issuer_setup( @@ -213,9 +270,32 @@ fn anoncreds_with_multiple_credentials_per_request() { ); presentations.push(p) } + // 5. Verifier verifies one presentation per request - let results = mock.verifer_verifies_presentations_for_requests(presentations, &reqs); + // + // Without override fails + let overrides = vec![None; 5]; + let results = + mock.verifer_verifies_presentations_for_requests(&presentations, &reqs, &overrides); + assert!(results[0].is_ok()); + assert!(results[4].is_ok()); + assert!(results[1].is_err()); + assert!(results[2].is_err()); + assert!(results[3].is_err()); - assert!(results[0]); - assert!(results[1]); + // Create overrides for timestamps + let id = RevocationRegistryDefinitionId::new_unchecked(REV_REG_ID_1); + let override_rev1 = HashMap::from([(&id, HashMap::from([(LOCAL_FROM, OVERRIDE_LOCAL_FROM)]))]); + let overrides = vec![ + None, + Some(&override_rev1), + Some(&override_rev1), + Some(&override_rev1), + None, + ]; + let results = + mock.verifer_verifies_presentations_for_requests(&presentations, &reqs, &overrides); + assert!(results[1].is_ok()); + assert!(results[2].is_ok()); + assert!(results[3].is_ok()); } diff --git a/tests/utils/mock.rs b/tests/utils/mock.rs index a17eec89..c707ef1a 100644 --- a/tests/utils/mock.rs +++ b/tests/utils/mock.rs @@ -23,6 +23,8 @@ use anoncreds::{ verifier, }; +pub struct TestError(String); + // {cred_def_id: { // schema_id, credential_values, support_revocation, rev_reg_id, rev_idx // }} @@ -33,6 +35,9 @@ pub type IssuerValues<'a> = // attribute_per_credential, predicate_for_credential }} pub type ProverValues<'a> = HashMap<&'a str, (Vec<&'a str>, Vec<&'a str>)>; +// { rev_reg_def_id: {req_timestamp, override_timestamp} } +pub type Override<'a> = HashMap<&'a RevocationRegistryDefinitionId, HashMap>; + #[derive(Debug)] pub struct Mock<'a> { pub issuer_wallets: HashMap<&'a str, IssuerWallet<'a>>, @@ -69,9 +74,10 @@ impl<'a> Mock<'a> { pub fn verifer_verifies_presentations_for_requests( &self, - presentations: Vec, + presentations: &[Presentation], reqs: &[PresentationRequest], - ) -> Vec { + overrides: &[Option<&Override>], + ) -> Vec> { let mut results = vec![]; let schemas: HashMap<&SchemaId, &Schema> = HashMap::from_iter(self.ledger.schemas.iter()); let cred_defs: HashMap<&CredentialDefinitionId, &CredentialDefinition> = @@ -82,7 +88,6 @@ impl<'a> Mock<'a> { .revcation_list .iter() .for_each(|(_, v)| v.iter().for_each(|(_, list)| rev_status_lists.push(list))); - let rev_reg_def_map = HashMap::from_iter(self.ledger.rev_reg_defs.iter()); for (i, presentation) in presentations.iter().enumerate() { @@ -93,9 +98,9 @@ impl<'a> Mock<'a> { &cred_defs, Some(&rev_reg_def_map), Some(rev_status_lists.clone()), - None, + overrides[i], ) - .expect("Error verifying presentation"); + .map_err(|e| TestError(e.to_string())); results.push(valid); } results @@ -413,10 +418,12 @@ impl<'a> Mock<'a> { .get(cred.cred_def_id.to_string().as_str()) .unwrap(); { - let (rev_state, timestamp) = match &cred.rev_reg_id { - Some(id) => self.prover_wallets[prover_id].rev_states.get(&id).unwrap(), - None => &(None, None), + let (rev_state, timestamp) = if let Some(id) = &cred.rev_reg_id { + self.prover_wallets[prover_id].rev_states.get(&id).unwrap() + } else { + &(None, None) }; + let mut cred1 = present.add_credential(cred, *timestamp, rev_state.as_ref()); for a in &values.0 { cred1.add_requested_attribute(a.clone(), true); diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs index d7de4f06..7d38b6c6 100644 --- a/tests/utils/mod.rs +++ b/tests/utils/mod.rs @@ -1,4 +1,4 @@ pub mod anoncreds; pub mod mock; -pub use mock::{IssuerValues, Mock, ProverValues}; +pub use mock::*;