diff --git a/libindy/src/commands/anoncreds/prover.rs b/libindy/src/commands/anoncreds/prover.rs index ccf77dd664..61464b7e3b 100644 --- a/libindy/src/commands/anoncreds/prover.rs +++ b/libindy/src/commands/anoncreds/prover.rs @@ -19,7 +19,7 @@ use self::indy_crypto::utils::json::{JsonDecodable, JsonEncodable}; use super::tails::SDKTailsAccessor; use domain::anoncreds::schema::{Schema, schemas_map_to_schemas_v1_map}; -use domain::anoncreds::credential::{Credential, CredentialInfo}; +use domain::anoncreds::credential::{Credential, CredentialInfo, AttributeValues}; use domain::anoncreds::credential_definition::{CredentialDefinition, CredentialDefinitionV1, cred_defs_map_to_cred_defs_v1_map}; use domain::anoncreds::credential_offer::CredentialOffer; use domain::anoncreds::credential_request::{CredentialRequest, CredentialRequestMetadata}; @@ -805,8 +805,15 @@ impl ProverCommandExecutor { let (referent, credential) = self._get_credential(&credential_record)?; if let Some(predicate) = predicate_info { + + let cred_values_common_view: HashMap = + credential.values + .iter() + .map(|(key, value)| (attr_common_view(&key), value.clone())) + .collect(); + let satisfy = self.anoncreds_service.prover.attribute_satisfy_predicate(predicate, - &credential.values[&attr_common_view(&predicate.name)].encoded)?; + &cred_values_common_view[&attr_common_view(&predicate.name)].encoded)?; if !satisfy { continue; } } diff --git a/libindy/src/commands/ledger.rs b/libindy/src/commands/ledger.rs index 614f797ff9..731822fadf 100644 --- a/libindy/src/commands/ledger.rs +++ b/libindy/src/commands/ledger.rs @@ -388,15 +388,7 @@ impl LedgerCommandExecutor { CommonError::InvalidStructure(format!("Message is invalid json: {}", request))))); } - let mut message_without_signatures = request.clone(); - message_without_signatures.as_object_mut() - .map(|request| { - request.remove("signature"); - request.remove("signatures"); - request - }).ok_or(CommonError::InvalidState("Cannot deserialize request".to_string()))?; - - let serialized_request = serialize_signature(message_without_signatures)?; + let serialized_request = serialize_signature(request.clone())?; let signature = self.crypto_service.sign(&my_key, &serialized_request.as_bytes().to_vec())?; match signature_type { diff --git a/libindy/src/utils/crypto/signature_serializer.rs b/libindy/src/utils/crypto/signature_serializer.rs index 30dda6a69a..b55191a226 100644 --- a/libindy/src/utils/crypto/signature_serializer.rs +++ b/libindy/src/utils/crypto/signature_serializer.rs @@ -8,6 +8,10 @@ use errors::common::CommonError; use utils::crypto::hash::Hash; pub fn serialize_signature(v: Value) -> Result { + _serialize_signature(v, true) +} + +fn _serialize_signature(v: Value, is_top_level: bool) -> Result { match v { Value::Bool(value) => Ok(if value { "True".to_string() } else { "False".to_string() }), Value::Number(value) => Ok(value.to_string()), @@ -16,7 +20,7 @@ pub fn serialize_signature(v: Value) -> Result { let mut result = "".to_string(); let length = array.len(); for (index, element) in array.iter().enumerate() { - result += &serialize_signature(element.clone())?; + result += &_serialize_signature(element.clone(), false)?; if index < length - 1 { result += ","; } @@ -25,9 +29,14 @@ pub fn serialize_signature(v: Value) -> Result { } Value::Object(map) => { let mut result = "".to_string(); - let length = map.len(); - for (index, key) in map.keys().enumerate() { - if key == "signature" { continue; } // Skip signature field as in python code + let mut in_middle = false; + for key in map.keys() { + // Skip signature field at top level as in python code + if is_top_level && (key == "signature" || key == "fees" || key == "signatures") { continue; } + + if in_middle { + result += "|"; + } let mut value = map[key].clone(); if key == "raw" || key == "hash" || key == "enc" { @@ -35,10 +44,8 @@ pub fn serialize_signature(v: Value) -> Result { ctx.update(&value.as_str().ok_or(CommonError::InvalidState("Cannot update hash context".to_string()))?.as_bytes())?; value = Value::String(ctx.finish2()?.as_ref().to_hex()); } - result = result + key + ":" + &serialize_signature(value)?; - if index < length - 1 { - result += "|"; - } + result = result + key + ":" + &_serialize_signature(value, false)?; + in_middle = true; } Ok(result) } @@ -73,6 +80,34 @@ mod tests { assert_eq!(serialize_signature(msg).unwrap(), result) } + + #[test] + fn signature_serialize_works_for_skipped_fields() { + let data = r#"{ + "name": "John Doe", + "age": 43, + "operation": { + "hash": "cool hash", + "dest": 54 + }, + "fees": "fees1", + "signature": "sign1", + "signatures": "sign-m", + "phones": [ + "1234567", + "2345678", + {"rust": 5, "age": 1}, + 3 + ] + }"#; + let msg: Value = serde_json::from_str(data).unwrap(); + + let result = "age:43|name:John Doe|operation:dest:54|hash:46aa0c92129b33ee72ee1478d2ae62fa6e756869dedc6c858af3214a6fcf1904|phones:1234567,2345678,age:1|rust:5,3"; + + assert_eq!(serialize_signature(msg).unwrap(), result) + } + + #[test] fn signature_serialize_works_with_raw() { let data = r#"{ @@ -104,4 +139,4 @@ mod tests { let serialized = serialize_signature(v).unwrap(); assert_eq!(serialized, ""); } -} \ No newline at end of file +} diff --git a/libindy/tests/anoncreds.rs b/libindy/tests/anoncreds.rs index d352958e69..df58661b26 100644 --- a/libindy/tests/anoncreds.rs +++ b/libindy/tests/anoncreds.rs @@ -1985,6 +1985,33 @@ mod high_cases { WalletUtils::close_wallet(wallet_handle).unwrap(); } + + #[test] + fn prover_get_credentials_for_proof_req_works_for_predicate_uppercase() { + AnoncredsUtils::init_common_wallet(); + + let wallet_handle = WalletUtils::open_wallet(ANONCREDS_WALLET_CONFIG, WALLET_CREDENTIALS).unwrap(); + + let proof_req = json!({ + "nonce":"123432421212", + "name":"proof_req_1", + "version":"0.1", + "requested_attributes": json!({}), + "requested_predicates": json!({ + "predicate1_referent": json!({ "name":"AGe", "p_type":">=", "p_value":18 }) + }), + }).to_string(); + + let credentials_json = AnoncredsUtils::prover_get_credentials_for_proof_req(wallet_handle, &proof_req).unwrap(); + + let credentials: CredentialsForProofRequest = serde_json::from_str(&credentials_json).unwrap(); + assert_eq!(credentials.predicates.len(), 1); + + let credentials_for_predicate_1 = credentials.predicates.get("predicate1_referent").unwrap(); + assert_eq!(credentials_for_predicate_1.len(), 2); + + WalletUtils::close_wallet(wallet_handle).unwrap(); + } } mod predicate_restrictions_wql_format { diff --git a/libindy/tests/utils/anoncreds.rs b/libindy/tests/utils/anoncreds.rs index 3f5c1c8184..a594e93f39 100644 --- a/libindy/tests/utils/anoncreds.rs +++ b/libindy/tests/utils/anoncreds.rs @@ -548,7 +548,7 @@ impl AnoncredsUtils { "sex".to_string() => AttributeValues {raw: "male".to_string(), encoded: "2142657394558967239210949258394838228692050081607692519917028371144233115103".to_string()}, "name".to_string() => AttributeValues {raw: "Alexander".to_string(), encoded: "21332817548165488690172217217278169335".to_string()}, "height".to_string() => AttributeValues {raw: "170".to_string(), encoded: "170".to_string()}, - "age".to_string() => AttributeValues {raw: "28".to_string(), encoded: "28".to_string()} + "Age".to_string() => AttributeValues {raw: "28".to_string(), encoded: "28".to_string()} } } @@ -610,7 +610,7 @@ impl AnoncredsUtils { "sex".to_string() => "male".to_string(), "name".to_string() => "Alexander".to_string(), "height".to_string() => "170".to_string(), - "age".to_string() => "28".to_string() + "Age".to_string() => "28".to_string() } } }