Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikita Khateev authored Mar 19, 2019
2 parents f6d20ae + 10f2af1 commit 1b3c91f
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 47 deletions.
123 changes: 109 additions & 14 deletions vcx/libvcx/src/disclosed_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,14 @@ fn credential_def_identifiers(credentials: &str, proof_req: &ProofRequestData) -
}

fn _get_revocation_interval(attr_name: &str, proof_req: &ProofRequestData) -> VcxResult<Option<NonRevokedInterval>> {
let attr = proof_req.requested_attributes.get(attr_name)
.ok_or(VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, format!("Attribute not found for: {}", attr_name)))?;

Ok(attr.non_revoked.clone().or(proof_req.non_revoked.clone().or(None)))

// Todo: Handle case for predicates
if let Some(attr) = proof_req.requested_attributes.get(attr_name) {
Ok(attr.non_revoked.clone().or(proof_req.non_revoked.clone().or(None)))
} else if let Some(attr) = proof_req.requested_predicates.get(attr_name) {
// Handle case for predicates
Ok(attr.non_revoked.clone().or(proof_req.non_revoked.clone().or(None)))
} else {
Err(VcxError::from_msg(VcxErrorKind::InvalidProofCredentialData, format!("Attribute not found for: {}", attr_name)))
}
}

// Also updates timestamp in credentials_identifiers
Expand Down Expand Up @@ -300,21 +302,35 @@ impl DisclosedProof {
Ok(rtn.to_string())
}

fn build_requested_credentials_json(&self, credentials_identifiers: &Vec<CredInfo>, self_attested_attrs: &str) -> VcxResult<String> {
fn build_requested_credentials_json(&self,
credentials_identifiers: &Vec<CredInfo>,
self_attested_attrs: &str,
proof_req: &ProofRequestData) -> VcxResult<String> {
let mut rtn: Value = json!({
"self_attested_attributes":{},
"requested_attributes":{},
"requested_predicates":{}
});
//Todo: need to do same for predicates and self_attested
//Todo: need to handle if the attribute is not revealed
// do same for predicates and self_attested
if let Value::Object(ref mut map) = rtn["requested_attributes"] {
for ref cred_info in credentials_identifiers {
let insert_val = json!({"cred_id": cred_info.referent, "revealed": true, "timestamp": cred_info.timestamp});
map.insert(cred_info.requested_attr.to_owned(), insert_val);
if let Some(ref attr) = proof_req.requested_attributes.get(&cred_info.requested_attr) {
let insert_val = json!({"cred_id": cred_info.referent, "revealed": true, "timestamp": cred_info.timestamp});
map.insert(cred_info.requested_attr.to_owned(), insert_val);
}
}
}

if let Value::Object(ref mut map) = rtn["requested_predicates"] {
for ref cred_info in credentials_identifiers {
if let Some(ref attr) = proof_req.requested_predicates.get(&cred_info.requested_attr) {
let insert_val = json!({"cred_id": cred_info.referent, "timestamp": cred_info.timestamp});
map.insert(cred_info.requested_attr.to_owned(), insert_val);
}
}
}

// handle if the attribute is not revealed
let self_attested_attrs: Value = serde_json::from_str(self_attested_attrs)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize self attested attributes: {}", err)))?;
rtn["self_attested_attributes"] = self_attested_attrs;
Expand All @@ -333,10 +349,13 @@ impl DisclosedProof {
let proof_req_data_json = serde_json::to_string(&proof_req.proof_request_data)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize proof request: {}", err)))?;

let mut credentials_identifiers = credential_def_identifiers(credentials, &proof_req.proof_request_data)?;
let mut credentials_identifiers = credential_def_identifiers(credentials,
&proof_req.proof_request_data)?;

let revoc_states_json = build_rev_states_json(&mut credentials_identifiers)?;
let requested_credentials = self.build_requested_credentials_json(&credentials_identifiers, self_attested_attrs)?;
let requested_credentials = self.build_requested_credentials_json(&credentials_identifiers,
self_attested_attrs,
&proof_req.proof_request_data)?;

let schemas_json = self.build_schemas_json(&credentials_identifiers)?;
let credential_defs_json = self.build_cred_def_json(&credentials_identifiers)?;
Expand Down Expand Up @@ -829,7 +848,22 @@ mod tests {
});

let proof: DisclosedProof = Default::default();
let requested_credential = proof.build_requested_credentials_json(&creds, &self_attested_attrs).unwrap();
let proof_req = json!({
"nonce": "123432421212",
"name": "proof_req_1",
"version": "0.1",
"requested_attributes": {
"height_1": {
"name": "height_1",
"non_revoked": {"from": 123, "to": 456}
},
"zip_2": { "name": "zip_2" }
},
"requested_predicates": {},
"non_revoked": {"from": 098, "to": 123}
});
let proof_req: ProofRequestData = serde_json::from_value(proof_req).unwrap();
let requested_credential = proof.build_requested_credentials_json(&creds, &self_attested_attrs, &proof_req).unwrap();
assert_eq!(test.to_string(), requested_credential);
}

Expand Down Expand Up @@ -1207,6 +1241,67 @@ mod tests {
assert!(generated_proof.is_ok());
}

#[cfg(feature = "pool_tests")]
#[test]
fn test_generate_proof_with_predicates() {
init!("ledger");
let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap();
let (schema_id, _, cred_def_id, _, _, _, _, cred_id, _, _) = ::utils::libindy::anoncreds::tests::create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, true);
let mut proof_req = ProofRequestMessage::create();
let to = time::get_time().sec;
let indy_proof_req = json!({
"nonce": "123432421212",
"name": "proof_req_1",
"version": "0.1",
"requested_attributes": {
"address1_1": {
"name": "address1",
"restrictions": [{"issuer_did": did}],
"non_revoked": {"from": 123, "to": to}
},
"zip_2": { "name": "zip" }
},
"self_attested_attr_3": json!({
"name":"self_attested_attr",
}),
"requested_predicates": json!({
"zip_3": {"name":"zip", "p_type":">=", "p_value":18}
}),
"non_revoked": {"from": 098, "to": to}
}).to_string();
proof_req.proof_request_data = serde_json::from_str(&indy_proof_req).unwrap();

let mut proof: DisclosedProof = Default::default();
proof.proof_request = Some(proof_req);
proof.link_secret_alias = "main".to_string();

let all_creds: Value = serde_json::from_str(&proof.retrieve_credentials().unwrap()).unwrap();
let selected_credentials: Value = json!({
"attrs":{
"address1_1": {
"credential": all_creds["attrs"]["address1_1"][0],
"tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()
},
"zip_2": {
"credential": all_creds["attrs"]["zip_2"][0],
"tails_file": get_temp_dir_path(Some(TEST_TAILS_FILE)).to_str().unwrap().to_string()
},
},
"predicates":{
"zip_3": {
"credential": all_creds["attrs"]["zip_3"][0],
}
}
});

let self_attested: Value = json!({
"self_attested_attr_3":"attested_val"
});

let generated_proof = proof.generate_proof(&selected_credentials.to_string(), &self_attested.to_string());
assert!(generated_proof.is_ok());
}

#[test]
fn test_build_rev_states_json() {
init!("true");
Expand Down
1 change: 1 addition & 0 deletions vcx/libvcx/src/utils/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ pub static PROOF_LIBINDY: &str = r#"{"proofs":{"claim::1f927d68-8905-4188-afd6-3
pub static PROOF_REQUEST: &str = r#"{"name":"proof name","nonce":"2771519439","requested_attrs":{"height_0":{"issuer_did":"DunkM3x1y7S4ECgSL4Wkru","name":"height","schema_seq_no":694},"weight_1":{"issuer_did":"DunkM3x1y7S4ECgSL4Wkru","name":"weight","schema_seq_no":694}},"requested_predicates":{"age_2":{"attr_name":"age","p_type":"GE","issuer_did":"DunkM3x1y7S4ECgSL4Wkru","schema_seq_no":694,"value":18}},"version":"0.1"}"#;

pub static REQUESTED_ATTRIBUTES: &str = "requested_attributes";
pub static PROOF_REQUESTED_PREDICATES: &str = "requested_predicates";
pub static ATTRS: &str = "attrs";
pub static ENTERPRISE_PREFIX: &str = "enterprise";
pub static CONSUMER_PREFIX: &str = "consumer";
Expand Down
170 changes: 149 additions & 21 deletions vcx/libvcx/src/utils/libindy/anoncreds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use indy::{anoncreds, blob_storage, ledger};
use time;

use settings;
use utils::constants::{LIBINDY_CRED_OFFER, REQUESTED_ATTRIBUTES, ATTRS, REV_STATE_JSON};
use utils::libindy::{error_codes::map_rust_indy_sdk_error, mock_libindy_rc, wallet::get_wallet_handle};
use utils::constants::{ LIBINDY_CRED_OFFER, REQUESTED_ATTRIBUTES, PROOF_REQUESTED_PREDICATES, ATTRS, REV_STATE_JSON};
use utils::libindy::{ error_codes::map_rust_indy_sdk_error, mock_libindy_rc, wallet::get_wallet_handle };
use utils::libindy::payments::{pay_for_txn, PaymentTxn};
use utils::libindy::ledger::*;
use utils::constants::{SCHEMA_ID, SCHEMA_JSON, SCHEMA_TXN_TYPE, CRED_DEF_ID, CRED_DEF_JSON, CRED_DEF_TXN_TYPE, REV_REG_DEF_TXN_TYPE, REV_REG_DELTA_TXN_TYPE, REVOC_REG_TYPE, rev_def_json, REV_REG_ID, REV_REG_DELTA_JSON, REV_REG_JSON};
Expand Down Expand Up @@ -150,28 +150,47 @@ pub fn libindy_prover_get_credentials_for_proof_req(proof_req: &str) -> VcxResul

// since the search_credentials_for_proof request validates that the proof_req is properly structured, this get()
// fn should never fail, unless libindy changes their formats.
let requested_attributes: Option<Map<String, Value>> = proof_request_json.get(REQUESTED_ATTRIBUTES)
let requested_attributes:Option<Map<String,Value>> = proof_request_json.get(REQUESTED_ATTRIBUTES)
.and_then(|v| {
serde_json::from_value(v.clone())
.map_err(|_| {
error!("Invalid Json Parsing of Requested Attributes Retrieved From Libindy. Did Libindy change its structure?");
}).ok()
serde_json::from_value(v.clone()).map_err(|_| {
error!("Invalid Json Parsing of Requested Attributes Retrieved From Libindy. Did Libindy change its structure?");
}).ok()
});

let requested_predicates:Option<Map<String,Value>> = proof_request_json.get(PROOF_REQUESTED_PREDICATES).and_then(|v| {
serde_json::from_value(v.clone()).map_err(|_| {
error!("Invalid Json Parsing of Requested Predicates Retrieved From Libindy. Did Libindy change its structure?");
}).ok()
});

// handle special case of "empty because json is bad" vs "empty because no attributes sepected"
if requested_attributes == None && requested_predicates == None {
return Err(VcxError::from_msg(VcxErrorKind::InvalidAttributesStructure, "Invalid Json Parsing of Requested Attributes Retrieved From Libindy"));
}

match requested_attributes {
Some(attrs) => {
let search_handle = anoncreds::prover_search_credentials_for_proof_req(wallet_handle, proof_req, None)
.wait()
.map_err(map_rust_indy_sdk_error)?;
let creds: String = fetch_credentials(search_handle, attrs)?;
// should an error on closing a search handle throw an error, or just a warning?
// for now we're are just outputting to the user that there is an issue, and continuing on.
let _ = close_search_handle(search_handle);
Ok(creds)
}
None => {
Err(VcxError::from_msg(VcxErrorKind::InvalidAttributesStructure, "Invalid Json Parsing of Requested Attributes Retrieved From Libindy"))
}
let mut fetch_attrs: Map<String, Value> = match requested_attributes {
Some(attrs) => attrs.clone(),
None => Map::new()
};
match requested_predicates {
Some(attrs) => fetch_attrs.extend(attrs),
None => ()
}
if 0 < fetch_attrs.len() {
let search_handle = anoncreds::prover_search_credentials_for_proof_req(wallet_handle, proof_req, None)
.wait()
.map_err(|ec| {
error!("Opening Indy Search for Credentials Failed");
map_rust_indy_sdk_error(ec)
})?;
let creds: String = fetch_credentials(search_handle, fetch_attrs)?;

// should an error on closing a search handle throw an error, or just a warning?
// for now we're are just outputting to the user that there is an issue, and continuing on.
let _ = close_search_handle(search_handle);
Ok(creds)
} else {
Ok("{}".to_string())
}
}

Expand Down Expand Up @@ -665,6 +684,77 @@ pub mod tests {
(proof_req, proof)
}

pub fn create_proof_with_predicate(include_predicate_cred: bool) -> (String, String, String, String) {
let did = settings::get_config_value(settings::CONFIG_INSTITUTION_DID).unwrap();
let (schema_id, schema_json, cred_def_id, cred_def_json, offer, req, req_meta, cred_id, _, _)
= create_and_store_credential(::utils::constants::DEFAULT_SCHEMA_ATTRS, false);

let proof_req = json!({
"nonce":"123432421212",
"name":"proof_req_1",
"version":"0.1",
"requested_attributes": json!({
"address1_1": json!({
"name":"address1",
"restrictions": [json!({ "issuer_did": did })]
}),
"self_attest_3": json!({
"name":"self_attest",
}),
}),
"requested_predicates": json!({
"zip_3": {"name":"zip", "p_type":">=", "p_value":18}
}),
}).to_string();

let requested_credentials_json;
if include_predicate_cred {
requested_credentials_json = 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();
} else {
requested_credentials_json = 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();
}

let schema_json: serde_json::Value = serde_json::from_str(&schema_json).unwrap();
let schemas = json!({
schema_id: schema_json,
}).to_string();

let cred_def_json: serde_json::Value = serde_json::from_str(&cred_def_json).unwrap();
let cred_defs = json!({
cred_def_id: cred_def_json,
}).to_string();

libindy_prover_get_credentials_for_proof_req(&proof_req).unwrap();

let proof = libindy_prover_create_proof(
&proof_req,
&requested_credentials_json,
"main",
&schemas,
&cred_defs,
None).unwrap();
(schemas, cred_defs, proof_req, proof)
}

#[cfg(feature = "pool_tests")]
#[test]
fn test_prover_verify_proof() {
Expand All @@ -685,6 +775,44 @@ pub mod tests {
assert!(proof_validation, true);
}

#[cfg(feature = "pool_tests")]
#[test]
fn test_prover_verify_proof_with_predicate_success_case() {
init!("ledger");
let (schemas, cred_defs, proof_req, proof) = create_proof_with_predicate(true);

let result = libindy_verifier_verify_proof(
&proof_req,
&proof,
&schemas,
&cred_defs,
"{}",
"{}",
);

assert!(result.is_ok());
let proof_validation = result.unwrap();
assert!(proof_validation, true);
}

#[cfg(feature = "pool_tests")]
#[test]
fn test_prover_verify_proof_with_predicate_fail_case() {
init!("ledger");
let (schemas, cred_defs, proof_req, proof) = create_proof_with_predicate(false);

let result = libindy_verifier_verify_proof(
&proof_req,
&proof,
&schemas,
&cred_defs,
"{}",
"{}",
);

assert!(!result.is_ok());
}

#[cfg(feature = "pool_tests")]
#[test]
fn tests_libindy_prover_get_credentials() {
Expand Down
Loading

0 comments on commit 1b3c91f

Please sign in to comment.