Skip to content

Commit

Permalink
CredxAnoncreds verifier functionality support (#708)
Browse files Browse the repository at this point in the history
* impl, now need to test

Signed-off-by: gmulhearn <gmulhearn@proton.me>

* try some tests in the pipeline

Signed-off-by: gmulhearn <gmulhearn@proton.me>

* more hasmap as ref usages

Signed-off-by: gmulhearn <gmulhearn@proton.me>

* pre-format for merge

Signed-off-by: gmulhearn <gmulhearn@proton.me>

* map proof rejected error

Signed-off-by: gmulhearn <gmulhearn@proton.me>

* seems to be mapping

Signed-off-by: gmulhearn <gmulhearn@proton.me>

* improvement to check

Signed-off-by: gmulhearn <gmulhearn@proton.me>

Signed-off-by: gmulhearn <gmulhearn@proton.me>
  • Loading branch information
gmulhearn authored Jan 13, 2023
1 parent a3c3c91 commit 4e4f02a
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 42 deletions.
29 changes: 13 additions & 16 deletions aries_vcx/src/common/proofs/verifier/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ pub mod unit_tests {

#[tokio::test]
async fn test_proof_self_attested_proof_validation() {
SetupProfile::run_indy(|setup| async move {
let holder_setup = init_holder_setup_in_indy_context(&setup).await;

SetupProfile::run(|setup| async move {
let requested_attrs = json!([
json!({
"name":"address1",
Expand All @@ -83,7 +81,7 @@ pub mod unit_tests {
let revocation_details = r#"{"support_revocation":false}"#.to_string();
let name = "Optional".to_owned();

let proof_req_json = ProofRequestData::create(&holder_setup.profile, &name)
let proof_req_json = ProofRequestData::create(&setup.profile, &name)
.await
.unwrap()
.set_requested_attributes_as_string(requested_attrs)
Expand All @@ -95,7 +93,7 @@ pub mod unit_tests {

let proof_req_json = serde_json::to_string(&proof_req_json).unwrap();

let anoncreds = Arc::clone(&holder_setup.profile).inject_anoncreds();
let anoncreds = Arc::clone(&setup.profile).inject_anoncreds();
let prover_proof_json = anoncreds
.prover_create_proof(
&proof_req_json,
Expand Down Expand Up @@ -194,19 +192,18 @@ pub mod unit_tests {
)
.await
.unwrap();
// TODO: should return a new AriesVcxErrorKind err instead of AriesVcxErrorKind::VdrToolsError
assert_eq!(
validate_indy_proof(&setup.profile, &prover_proof_json, &proof_req_json)
validate_indy_proof(&holder_setup.profile, &prover_proof_json, &proof_req_json)
.await
.unwrap_err()
.kind(),
AriesVcxErrorKind::VdrToolsError(405)
); // AnoncredsProofRejected
AriesVcxErrorKind::ProofRejected
);

let mut proof_req_json: serde_json::Value = serde_json::from_str(&proof_req_json).unwrap();
proof_req_json["requested_attributes"]["attribute_0"]["restrictions"] = json!({});
assert_eq!(
validate_indy_proof(&setup.profile, &prover_proof_json, &proof_req_json.to_string())
validate_indy_proof(&holder_setup.profile, &prover_proof_json, &proof_req_json.to_string())
.await
.unwrap(),
true
Expand Down Expand Up @@ -285,7 +282,7 @@ pub mod unit_tests {
.await
.unwrap();
assert_eq!(
validate_indy_proof(&setup.profile, &prover_proof_json, &proof_req_json)
validate_indy_proof(&holder_setup.profile, &prover_proof_json, &proof_req_json)
.await
.unwrap(),
true
Expand All @@ -297,7 +294,7 @@ pub mod unit_tests {
let prover_proof_json = serde_json::to_string(&proof_obj).unwrap();

assert_eq!(
validate_indy_proof(&setup.profile, &prover_proof_json, &proof_req_json)
validate_indy_proof(&holder_setup.profile, &prover_proof_json, &proof_req_json)
.await
.unwrap_err()
.kind(),
Expand All @@ -310,7 +307,7 @@ pub mod unit_tests {
let prover_proof_json = serde_json::to_string(&proof_obj).unwrap();

assert_eq!(
validate_indy_proof(&setup.profile, &prover_proof_json, &proof_req_json)
validate_indy_proof(&holder_setup.profile, &prover_proof_json, &proof_req_json)
.await
.unwrap_err()
.kind(),
Expand Down Expand Up @@ -338,7 +335,7 @@ pub mod integration_tests {
let (schemas, cred_defs, proof_req, proof) =
create_indy_proof(&setup.profile, &holder_setup.profile, &setup.institution_did).await;

let anoncreds = Arc::clone(&setup.profile).inject_anoncreds();
let anoncreds = Arc::clone(&holder_setup.profile).inject_anoncreds();
let proof_validation = anoncreds
.verifier_verify_proof(&proof_req, &proof, &schemas, &cred_defs, "{}", "{}")
.await
Expand All @@ -357,7 +354,7 @@ pub mod integration_tests {
let (schemas, cred_defs, proof_req, proof) =
create_proof_with_predicate(&setup.profile, &holder_setup.profile, &setup.institution_did, true).await;

let anoncreds = Arc::clone(&setup.profile).inject_anoncreds();
let anoncreds = Arc::clone(&holder_setup.profile).inject_anoncreds();
let proof_validation = anoncreds
.verifier_verify_proof(&proof_req, &proof, &schemas, &cred_defs, "{}", "{}")
.await
Expand All @@ -376,7 +373,7 @@ pub mod integration_tests {
let (schemas, cred_defs, proof_req, proof) =
create_proof_with_predicate(&setup.profile, &holder_setup.profile, &setup.institution_did, false).await;

let anoncreds = Arc::clone(&setup.profile).inject_anoncreds();
let anoncreds = Arc::clone(&holder_setup.profile).inject_anoncreds();
anoncreds
.verifier_verify_proof(&proof_req, &proof, &schemas, &cred_defs, "{}", "{}")
.await
Expand Down
2 changes: 2 additions & 0 deletions aries_vcx/src/errors/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub enum AriesVcxErrorKind {
InvalidProofCredentialData,
#[error("Proof Request Passed into Libindy Call Was Invalid")]
InvalidProofRequest,
#[error("The proof was rejected")]
ProofRejected,

// Schema
#[error("No Schema for that schema sequence number")]
Expand Down
13 changes: 11 additions & 2 deletions aries_vcx/src/errors/mapping_credx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,23 @@ use indy_credx::Error as CredxError;

impl From<CredxError> for AriesVcxError {
fn from(err: CredxError) -> Self {
match err.kind() {
// Credx will occasionally wrap the real error within the `cause` of an ErrorKind::Input error type
// So we use this cause error if the cause exists and can be downcast to an credxerror
let cause = if err.kind() == indy_credx::ErrorKind::Input {
err.cause.as_ref().and_then(|x| x.downcast_ref::<CredxError>())
} else {
None
};
let e = cause.unwrap_or(&err);

match e.kind() {
indy_credx::ErrorKind::Input => AriesVcxError::from_msg(AriesVcxErrorKind::InvalidInput, err),
indy_credx::ErrorKind::IOError => AriesVcxError::from_msg(AriesVcxErrorKind::IOError, err),
indy_credx::ErrorKind::InvalidState => AriesVcxError::from_msg(AriesVcxErrorKind::InvalidState, err),
indy_credx::ErrorKind::Unexpected => AriesVcxError::from_msg(AriesVcxErrorKind::UnknownError, err),
indy_credx::ErrorKind::CredentialRevoked => AriesVcxError::from_msg(AriesVcxErrorKind::InvalidState, err),
indy_credx::ErrorKind::InvalidUserRevocId => AriesVcxError::from_msg(AriesVcxErrorKind::InvalidInput, err),
indy_credx::ErrorKind::ProofRejected => AriesVcxError::from_msg(AriesVcxErrorKind::InvalidState, err),
indy_credx::ErrorKind::ProofRejected => AriesVcxError::from_msg(AriesVcxErrorKind::ProofRejected, err),
indy_credx::ErrorKind::RevocationRegistryFull => {
AriesVcxError::from_msg(AriesVcxErrorKind::InvalidState, err)
}
Expand Down
1 change: 1 addition & 0 deletions aries_vcx/src/errors/mapping_vdrtools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl From<IndyErrorKind> for AriesVcxErrorKind {
UnknownWalletStorageType => AriesVcxErrorKind::InvalidConfiguration,
WalletStorageTypeAlreadyRegistered => AriesVcxErrorKind::InvalidConfiguration,
WalletAccessFailed => AriesVcxErrorKind::WalletAccessFailed,
ProofRejected => AriesVcxErrorKind::ProofRejected,
_ => {
let err_code = types::ErrorCode::from(indy) as u32;
AriesVcxErrorKind::VdrToolsError(err_code)
Expand Down
71 changes: 51 additions & 20 deletions aries_vcx/src/plugins/anoncreds/credx_anoncreds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use async_trait::async_trait;
use credx::{
types::{
Credential as CredxCredential, CredentialDefinitionId, CredentialRequestMetadata, CredentialRevocationState,
DidValue, MasterSecret, PresentCredentials, PresentationRequest, RevocationRegistryDefinition,
RevocationRegistryDelta, Schema, SchemaId,
DidValue, MasterSecret, PresentCredentials, Presentation, PresentationRequest, RevocationRegistry,
RevocationRegistryDefinition, RevocationRegistryDelta, RevocationRegistryId, Schema, SchemaId,
},
ursa::bn::BigNumber,
};
Expand Down Expand Up @@ -154,7 +154,36 @@ impl BaseAnonCreds for IndyCredxAnonCreds {
rev_reg_defs_json,
rev_regs_json,
);
Err(unimplemented_method_err("credx verifier_verify_proof"))

let presentation: Presentation = serde_json::from_str(proof_json)?;
let pres_req: PresentationRequest = serde_json::from_str(proof_req_json)?;

let schemas: HashMap<SchemaId, Schema> = serde_json::from_str(schemas_json)?;
let cred_defs: HashMap<CredentialDefinitionId, CredentialDefinition> =
serde_json::from_str(credential_defs_json)?;

let rev_reg_defs: Option<HashMap<RevocationRegistryId, RevocationRegistryDefinition>> =
serde_json::from_str(rev_reg_defs_json)?;

let rev_regs: Option<HashMap<RevocationRegistryId, HashMap<u64, RevocationRegistry>>> =
serde_json::from_str(rev_regs_json)?;
let rev_regs: Option<HashMap<RevocationRegistryId, HashMap<u64, &RevocationRegistry>>> =
rev_regs.as_ref().map(|regs| {
let mut new_regs: HashMap<RevocationRegistryId, HashMap<u64, &RevocationRegistry>> = HashMap::new();
for (k, v) in regs {
new_regs.insert(k.clone(), hashmap_as_ref(v));
}
new_regs
});

Ok(credx::verifier::verify_presentation(
&presentation,
&pres_req,
&hashmap_as_ref(&schemas),
&hashmap_as_ref(&cred_defs),
rev_reg_defs.as_ref().map(|regs| hashmap_as_ref(regs)).as_ref(),
rev_regs.as_ref(),
)?)
}

async fn issuer_create_and_store_revoc_reg(
Expand Down Expand Up @@ -234,8 +263,8 @@ impl BaseAnonCreds for IndyCredxAnonCreds {
None
};

let _schemas: HashMap<SchemaId, Schema> = serde_json::from_str(schemas_json)?;
let _cred_defs: HashMap<CredentialDefinitionId, CredentialDefinition> =
let schemas: HashMap<SchemaId, Schema> = serde_json::from_str(schemas_json)?;
let cred_defs: HashMap<CredentialDefinitionId, CredentialDefinition> =
serde_json::from_str(credential_defs_json)?;

let mut present_credentials: PresentCredentials = PresentCredentials::new();
Expand Down Expand Up @@ -334,25 +363,13 @@ impl BaseAnonCreds for IndyCredxAnonCreds {

let link_secret = self.get_link_secret(link_secret_id).await?;

let mut schemas: HashMap<SchemaId, &Schema> = HashMap::new();

for (k, v) in _schemas.iter() {
schemas.insert(k.clone(), v);
}

let mut cred_defs: HashMap<CredentialDefinitionId, &CredentialDefinition> = HashMap::new();

for (k, v) in _cred_defs.iter() {
cred_defs.insert(k.clone(), v);
}

let presentation = credx::prover::create_presentation(
&pres_req,
present_credentials,
self_attested,
&link_secret,
&schemas,
&cred_defs,
&hashmap_as_ref(&schemas),
&hashmap_as_ref(&cred_defs),
)?;

Ok(serde_json::to_string(&presentation)?)
Expand Down Expand Up @@ -748,6 +765,21 @@ fn unimplemented_method_err(method_name: &str) -> AriesVcxError {
)
}

// common transformation requirement in credx
fn hashmap_as_ref<'a, T, U>(map: &'a HashMap<T, U>) -> HashMap<T, &'a U>
where
T: std::hash::Hash,
T: std::cmp::Eq,
T: std::clone::Clone,
{
let mut new_map: HashMap<T, &U> = HashMap::new();
for (k, v) in map.iter() {
new_map.insert(k.clone(), v);
}

new_map
}

#[cfg(test)]
#[cfg(feature = "general_test")]
mod unit_tests {
Expand All @@ -767,7 +799,6 @@ mod unit_tests {
let profile = mock_profile();
let anoncreds: Box<dyn BaseAnonCreds> = Box::new(IndyCredxAnonCreds::new(profile));

assert_unimplemented(anoncreds.verifier_verify_proof("", "", "", "", "", "").await);
assert_unimplemented(anoncreds.issuer_create_and_store_revoc_reg("", "", "", 0, "").await);
assert_unimplemented(
anoncreds
Expand Down
6 changes: 2 additions & 4 deletions aries_vcx/src/utils/devsetup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ impl SetupProfile {
}

pub async fn init() -> SetupProfile {
init_test_logging();
set_test_configs();
if SetupProfile::should_run_modular() {
info!("SetupProfile >> using modular profile");
SetupProfile::init_modular().await
Expand All @@ -372,8 +374,6 @@ impl SetupProfile {
// FUTURE - ideally no tests should be using this method, they should be using the generic init
// after modular profile Anoncreds/Ledger methods have all been implemented, all tests should use init()
async fn init_indy() -> SetupProfile {
init_test_logging();
set_test_configs();
let (institution_did, wallet_handle) = setup_issuer_wallet().await;

settings::set_config_value(
Expand All @@ -399,8 +399,6 @@ impl SetupProfile {
}

async fn init_modular() -> SetupProfile {
init_test_logging();
set_test_configs();
let (institution_did, wallet_handle) = setup_issuer_wallet().await;

let genesis_file_path = create_tmp_genesis_txn_file();
Expand Down
2 changes: 2 additions & 0 deletions libvcx/src/errors/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ pub enum LibvcxErrorKind {
InvalidProofCredentialData,
#[error("Proof Request Passed into Libindy Call Was Invalid")]
InvalidProofRequest,
#[error("The proof was rejected")]
ProofRejected,

// Schema
#[error("Could not create schema")]
Expand Down
1 change: 1 addition & 0 deletions libvcx/src/errors/mapping_from_ariesvcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ impl From<AriesVcxErrorKind> for LibvcxErrorKind {
AriesVcxErrorKind::NoAgentInformation => LibvcxErrorKind::NoAgentInformation,
AriesVcxErrorKind::InvalidMessageFormat => LibvcxErrorKind::InvalidMessageFormat,
AriesVcxErrorKind::LedgerItemNotFound => LibvcxErrorKind::LedgerItemNotFound,
AriesVcxErrorKind::ProofRejected => LibvcxErrorKind::ProofRejected,
}
}
}

0 comments on commit 4e4f02a

Please sign in to comment.