From 66caeca450fb45a45c99fade899f987c49bb5088 Mon Sep 17 00:00:00 2001 From: bwty Date: Mon, 9 Jan 2023 21:49:36 +0700 Subject: [PATCH] feat: test mock suite and support both non/revocable Signed-off-by: bwty --- anoncreds/src/services/verifier.rs | 193 ++++++++++-------------- anoncreds/tests/anoncreds_demos.rs | 95 ++++++------ anoncreds/tests/multiple-credentials.rs | 14 +- anoncreds/tests/utils/mock.rs | 11 +- 4 files changed, 138 insertions(+), 175 deletions(-) diff --git a/anoncreds/src/services/verifier.rs b/anoncreds/src/services/verifier.rs index 47189ea9..960351cd 100644 --- a/anoncreds/src/services/verifier.rs +++ b/anoncreds/src/services/verifier.rs @@ -76,21 +76,21 @@ pub fn verify_presentation( &received_self_attested_attrs, )?; - // makes sure the for revocable request or attribute, - // there is a timestamp in the `Identifier` - compare_timestamps_from_proof_and_request( - pres_req, - &received_revealed_attrs, - &received_unrevealed_attrs, - &received_self_attested_attrs, - &received_predicates, - &mut nrp_warnings, - )?; - let mut proof_verifier = CryptoVerifier::new_proof_verifier()?; let non_credential_schema = build_non_credential_schema()?; for sub_proof_index in 0..presentation.identifiers.len() { + let attrs_for_credential = get_revealed_attributes_for_credential( + sub_proof_index, + &presentation.requested_proof, + pres_req, + )?; + let predicates_for_credential = get_predicates_for_credential( + sub_proof_index, + &presentation.requested_proof, + pres_req, + )?; + let identifier = presentation.identifiers[sub_proof_index].clone(); let schema = schemas @@ -105,7 +105,18 @@ pub fn verify_presentation( ) })?; - let (rev_reg_def, rev_reg) = if let Some(timestamp) = identifier.timestamp { + // Checks that there is a NRP requirement in the request AND that credential is revocable + let (rev_reg_def, rev_reg) = if let (Some(timestamp), Some(_)) = + (identifier.timestamp, cred_def.value.revocation.as_ref()) + { + checks_nrp_is_provided( + &pres_req, + &attrs_for_credential, + &predicates_for_credential, + &identifier, + &mut nrp_warnings, + )?; + let rev_reg_id = identifier.rev_reg_id.clone().ok_or_else(|| { err_msg!("Timestamp provided but Revocation Registry Id not found") })?; @@ -155,17 +166,6 @@ pub fn verify_presentation( (None, None) }; - let attrs_for_credential = get_revealed_attributes_for_credential( - sub_proof_index, - &presentation.requested_proof, - pres_req, - )?; - let predicates_for_credential = get_predicates_for_credential( - sub_proof_index, - &presentation.requested_proof, - pres_req, - )?; - let credential_schema = build_credential_schema(&schema.attr_names.0)?; let sub_pres_request = build_sub_proof_request(&attrs_for_credential, &predicates_for_credential)?; @@ -191,7 +191,7 @@ pub fn verify_presentation( let valid = proof_verifier.verify(&presentation.proof, pres_req.nonce.as_native())?; trace!("verify <<< valid: {:?}", valid); - trace!("non_rev_proof_warnings <<<: {:?}", nrp_warnings); + trace!("non_rev_proof_warnings <<< {:?}", nrp_warnings); Ok((valid, nrp_warnings)) } @@ -307,54 +307,41 @@ fn compare_attr_from_proof_and_request( Ok(()) } -// This does not actually compare the non_revoke interval -// see `validate_timestamp` function comments -fn compare_timestamps_from_proof_and_request( +//checks_nrp_is_provided(pres_req.non_revoked, attrs_for_credential, predicates_for_credential, identifier, nrp_warnings)? +fn checks_nrp_is_provided( pres_req: &PresentationRequestPayload, - received_revealed_attrs: &HashMap, - received_unrevealed_attrs: &HashMap, - received_self_attested_attrs: &HashSet, - received_predicates: &HashMap, + attrs_for_credential: &[AttributeInfo], + predicates_for_credential: &[PredicateInfo], + identifier: &Identifier, nrp_warnings: &mut NonRevProofWarnings, ) -> Result<()> { let mut warnings = vec![]; - pres_req - .requested_attributes + attrs_for_credential .iter() - .map(|(referent, info)| { + .map(|info| { + let name = match (info.name.clone(), info.names.clone()) { + (Some(name), None) => name, + (None, Some(names)) => format!("{:?}", names), + _ => return Err(err_msg!("missing name / names for attribute")), + }; + validate_timestamp( &mut warnings, - received_revealed_attrs, - referent, + identifier, + &name, &pres_req.non_revoked, &info.non_revoked, ) - .or_else(|_| { - validate_timestamp( - &mut warnings, - received_unrevealed_attrs, - referent, - &pres_req.non_revoked, - &info.non_revoked, - ) - }) - .or_else(|_| { - received_self_attested_attrs - .get(referent) - .map(|_| ()) - .ok_or_else(|| err_msg!("Referent validation failed: {}", referent)) - }) }) .collect::>>()?; - pres_req - .requested_predicates + predicates_for_credential .iter() - .map(|(referent, info)| { + .map(|info| { validate_timestamp( &mut warnings, - received_predicates, - referent, + identifier, + &info.name, &pres_req.non_revoked, &info.non_revoked, ) @@ -364,7 +351,6 @@ fn compare_timestamps_from_proof_and_request( if !warnings.is_empty() { nrp_warnings.timestamps_out_of_range = Some(warnings); } - Ok(()) } @@ -384,17 +370,17 @@ fn compare_timestamps_from_proof_and_request( // a wanring is provided for the verifier to decide if they will reject the proof or not fn validate_timestamp( warnings: &mut Vec, - received_: &HashMap, - referent: &str, + identifier: &Identifier, + name: &str, global_interval: &Option, local_interval: &Option, ) -> Result<()> { if let Some(interval) = get_non_revoc_interval(global_interval, local_interval) { // If there is global or local interval, we compare the timestamp provided - if let Some(Some(ts)) = received_.get(referent).map(|attr| attr.timestamp) { + if let Some(ts) = identifier.timestamp { if ts.gt(&interval.to.unwrap_or(u64::MAX)) || ts.lt(&interval.from.unwrap_or(0)) { // We add to NonRevProofWarnings that the referent is out of range - warnings.push(referent.to_string()); + warnings.push(name.to_string()); } Ok(()) } else { @@ -1261,49 +1247,38 @@ mod tests { assert!(_process_operator("zip", &op, &filter, Some("NOT HERE")).is_err()); } - fn _received() -> HashMap { - let mut res: HashMap = HashMap::new(); - res.insert( - "referent_within_interval".to_string(), - Identifier { + fn _interval(from: Option, to: Option) -> NonRevocedInterval { + NonRevocedInterval { from, to } + } + + fn _get_identifier(identifier: &str) -> Identifier { + match identifier { + "within_interval" => Identifier { timestamp: Some(1234), schema_id: SchemaId::default(), cred_def_id: CredentialDefinitionId::default(), rev_reg_id: Some(RevocationRegistryId::default()), }, - ); - res.insert( - "referent_before_from".to_string(), - Identifier { + "before_from" => Identifier { timestamp: Some(1), schema_id: SchemaId::default(), cred_def_id: CredentialDefinitionId::default(), rev_reg_id: Some(RevocationRegistryId::default()), }, - ); - res.insert( - "referent_after_to".to_string(), - Identifier { + "after_to" => Identifier { timestamp: Some(4999), schema_id: SchemaId::default(), cred_def_id: CredentialDefinitionId::default(), rev_reg_id: Some(RevocationRegistryId::default()), }, - ); - res.insert( - "referent_none".to_string(), - Identifier { + "none" => Identifier { timestamp: None, schema_id: SchemaId::default(), cred_def_id: CredentialDefinitionId::default(), rev_reg_id: Some(RevocationRegistryId::default()), }, - ); - res - } - - fn _interval(from: Option, to: Option) -> NonRevocedInterval { - NonRevocedInterval { from, to } + _ => panic!("no such identifier"), + } } #[test] @@ -1311,8 +1286,8 @@ mod tests { let mut warnings: Vec = vec![]; validate_timestamp( &mut warnings, - &_received(), - "referent_within_interval", + &_get_identifier("within_interval"), + "within_interval", &None, &None, ) @@ -1325,8 +1300,8 @@ mod tests { let mut warnings: Vec = vec![]; validate_timestamp( &mut warnings, - &_received(), - "referent_within_interval", + &_get_identifier("within_interval"), + "within_interval", &Some(_interval(Some(FROM), Some(TO))), &None, ) @@ -1339,8 +1314,8 @@ mod tests { let mut warnings: Vec = vec![]; validate_timestamp( &mut warnings, - &_received(), - "referent_within_interval", + &_get_identifier("within_interval"), + "within_interval", &None, &Some(_interval(Some(FROM), Some(TO))), ) @@ -1353,13 +1328,13 @@ mod tests { let mut warnings: Vec = vec![]; validate_timestamp( &mut warnings, - &_received(), - "referent_before_from", + &_get_identifier("before_from"), + "before_from", &Some(_interval(Some(FROM), Some(TO))), &None, ) .unwrap(); - assert_eq!(warnings.pop().unwrap(), "referent_before_from"); + assert_eq!(warnings.pop().unwrap(), "before_from"); } #[test] @@ -1367,13 +1342,13 @@ mod tests { let mut warnings: Vec = vec![]; validate_timestamp( &mut warnings, - &_received(), - "referent_after_to", + &_get_identifier("after_to"), + "after_to", &Some(_interval(Some(FROM), Some(TO))), &None, ) .unwrap(); - assert_eq!(warnings.pop().unwrap(), "referent_after_to"); + assert_eq!(warnings.pop().unwrap(), "after_to"); } #[test] @@ -1381,21 +1356,21 @@ mod tests { let mut warnings: Vec = vec![]; validate_timestamp( &mut warnings, - &_received(), - "referent_within_interval", + &_get_identifier("within_interval"), + "within_interval", &Some(_interval(Some(FROM), Some(TO))), &Some(_interval(Some(FROM + 500), Some(TO))), ) .unwrap(); - assert_eq!(warnings.pop().unwrap(), "referent_within_interval"); + assert_eq!(warnings.pop().unwrap(), "within_interval"); } #[test] fn validate_timestamp_not_work_without_timestamp_for_global_interval() { validate_timestamp( &mut vec![], - &_received(), - "referent_none", + &_get_identifier("none"), + "none", &Some(_interval(Some(FROM), Some(TO))), &None, ) @@ -1406,20 +1381,8 @@ mod tests { fn validate_timestamp_fails_without_timestamp_for_local_interval() { validate_timestamp( &mut vec![], - &_received(), - "referent_none", - &None, - &Some(_interval(Some(FROM), Some(TO))), - ) - .unwrap_err(); - } - - #[test] - fn validate_timestamp_fails_without_refernt() { - validate_timestamp( - &mut vec![], - &_received(), - "referent_not_exist", + &_get_identifier("none"), + "none", &None, &Some(_interval(Some(FROM), Some(TO))), ) diff --git a/anoncreds/tests/anoncreds_demos.rs b/anoncreds/tests/anoncreds_demos.rs index fb97d574..825de2ac 100644 --- a/anoncreds/tests/anoncreds_demos.rs +++ b/anoncreds/tests/anoncreds_demos.rs @@ -27,8 +27,8 @@ use self::utils::anoncreds::ProverWallet; mod utils; -pub static SCHEMA_ID: &str = "mock:uri"; -pub static CRED_DEF_ID: &str = "mock:uri"; +pub static SCHEMA_ID: &str = "mock:uri:schema"; +pub static CRED_DEF_ID: &str = "mock:uri:1"; pub static ISSUER_ID: &str = "mock:issuer_id/path&q=bar"; pub const GVT_SCHEMA_NAME: &str = "gvt"; pub const GVT_SCHEMA_ATTRIBUTES: &[&str; 4] = &["name", "age", "sex", "height"]; @@ -135,7 +135,8 @@ fn anoncreds_works_for_single_issuer_single_prover() { }, "requested_predicates":{ "predicate1_referent":{"name":"age","p_type":">=","p_value":18} - } + }, + "non_revoked": {"from": 10, "to": 200} })) .expect("Error creating proof request"); @@ -254,8 +255,7 @@ fn anoncreds_with_revocation_works_for_single_issuer_single_prover() { .expect("Error creating gvt credential definition"); // This will create a tails file locally in the .tmp dir - let tf_path = "../.tmp"; - create_dir(tf_path) + create_dir(TF_PATH) .or_else(|e| -> Result<(), std::io::Error> { println!( "Tail file path creation error but test can still proceed {}", @@ -491,49 +491,6 @@ fn anoncreds_with_revocation_works_for_single_issuer_single_prover() { assert!(!valid); } -fn _create_presentation( - schemas: &HashMap<&SchemaId, &Schema>, - cred_defs: &HashMap<&CredentialDefinitionId, &CredentialDefinition>, - pres_request: &PresentationRequest, - prover_wallet: &ProverWallet, - rev_state_timestamp: Option, - rev_state: Option<&CredentialRevocationState>, -) -> Presentation { - let mut present = PresentCredentials::default(); - { - // Here we add credential with the timestamp of which the rev_state is updated to, - // also the rev_reg has to be provided for such a time. - // TODO: this timestamp is not verified by the `NonRevokedInterval`? - let mut cred1 = present.add_credential( - &prover_wallet.credentials[0], - rev_state_timestamp, - rev_state, - ); - cred1.add_requested_attribute("attr1_referent", true); - cred1.add_requested_attribute("attr2_referent", false); - cred1.add_requested_attribute("attr4_referent", true); - cred1.add_requested_predicate("predicate1_referent"); - } - - let mut self_attested = HashMap::new(); - let self_attested_phone = "8-800-300"; - self_attested.insert( - "attr3_referent".to_string(), - self_attested_phone.to_string(), - ); - - let presentation = prover::create_presentation( - pres_request, - present, - Some(self_attested), - &prover_wallet.master_secret, - schemas, - cred_defs, - ) - .expect("Error creating presentation"); - presentation -} - /* #[test] fn anoncreds_works_for_multiple_issuer_single_prover() { @@ -3416,3 +3373,45 @@ fn anoncreds_works_for_restrictions_as_empty_array() { wallet::close_and_delete_wallet(prover_wallet_handle, &prover_wallet_config).unwrap(); } */ + +fn _create_presentation( + schemas: &HashMap<&SchemaId, &Schema>, + cred_defs: &HashMap<&CredentialDefinitionId, &CredentialDefinition>, + pres_request: &PresentationRequest, + prover_wallet: &ProverWallet, + rev_state_timestamp: Option, + rev_state: Option<&CredentialRevocationState>, +) -> Presentation { + let mut present = PresentCredentials::default(); + { + // Here we add credential with the timestamp of which the rev_state is updated to, + // also the rev_reg has to be provided for such a time. + let mut cred1 = present.add_credential( + &prover_wallet.credentials[0], + rev_state_timestamp, + rev_state, + ); + cred1.add_requested_attribute("attr1_referent", true); + cred1.add_requested_attribute("attr2_referent", false); + cred1.add_requested_attribute("attr4_referent", true); + cred1.add_requested_predicate("predicate1_referent"); + } + + let mut self_attested = HashMap::new(); + let self_attested_phone = "8-800-300"; + self_attested.insert( + "attr3_referent".to_string(), + self_attested_phone.to_string(), + ); + + let presentation = prover::create_presentation( + pres_request, + present, + Some(self_attested), + &prover_wallet.master_secret, + schemas, + cred_defs, + ) + .expect("Error creating presentation"); + presentation +} diff --git a/anoncreds/tests/multiple-credentials.rs b/anoncreds/tests/multiple-credentials.rs index 567ac136..9ecbab67 100644 --- a/anoncreds/tests/multiple-credentials.rs +++ b/anoncreds/tests/multiple-credentials.rs @@ -116,11 +116,9 @@ fn anoncreds_with_multiple_credentials_per_request() { ("house", "Hufflepuff"), ("year", "1990"), ]), - // Issue 42 addresses if it is not revocable, - // revocation should still pass - true, - REV_REG_ID_2, - REV_IDX_2, + false, + "", + 0, ), ), ]); @@ -197,6 +195,8 @@ fn anoncreds_with_multiple_credentials_per_request() { // 5. Verifier verifies one presentation per request let results = mock.verifer_verifies_presentations_for_requests(presentations, &reqs); - assert!(results[0]); - assert!(results[1]); + assert!(results[0].0); + assert!(results[0].1.timestamps_out_of_range.is_some()); + assert!(results[1].0); + assert!(results[1].1.timestamps_out_of_range.is_some()); } diff --git a/anoncreds/tests/utils/mock.rs b/anoncreds/tests/utils/mock.rs index f8742fc9..e32fc5bd 100644 --- a/anoncreds/tests/utils/mock.rs +++ b/anoncreds/tests/utils/mock.rs @@ -10,7 +10,7 @@ use anoncreds::{ cred_offer::CredentialOffer, credential::Credential, presentation::Presentation, - rev_reg::{RevocationRegistry, RevocationRegistryId}, + rev_reg::{NonRevProofWarnings, RevocationRegistry, RevocationRegistryId}, rev_reg_def::RevocationRegistryDefinitionId, schema::{Schema, SchemaId}, }, @@ -18,7 +18,8 @@ use anoncreds::{ tails::{TailsFileReader, TailsFileWriter}, types::{ CredentialDefinitionConfig, CredentialRequest, CredentialRevocationConfig, - MakeCredentialValues, PresentCredentials, PresentationRequest, RegistryType, SignatureType, + CredentialRevocationState, MakeCredentialValues, PresentCredentials, PresentationRequest, + RegistryType, SignatureType, }, verifier, }; @@ -71,7 +72,7 @@ impl<'a> Mock<'a> { &self, presentations: Vec, reqs: &[PresentationRequest], - ) -> Vec { + ) -> Vec<(bool, NonRevProofWarnings)> { let mut results = vec![]; let schemas: HashMap<&SchemaId, &Schema> = HashMap::from_iter(self.ledger.schemas.iter()); let cred_defs: HashMap<&CredentialDefinitionId, &CredentialDefinition> = @@ -89,7 +90,7 @@ impl<'a> Mock<'a> { let rev_reg_def_map = HashMap::from_iter(self.ledger.rev_reg_defs.iter()); for (i, presentation) in presentations.iter().enumerate() { - let valid = verifier::verify_presentation( + let res = verifier::verify_presentation( &presentation, &reqs[i], &schemas, @@ -103,7 +104,7 @@ impl<'a> Mock<'a> { }))), ) .expect("Error verifying presentation"); - results.push(valid); + results.push(res); } results }