From d7e3206f9eb61e478449adc3a9ea33dd3ca35bce Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Fri, 3 Nov 2023 17:17:01 +0300 Subject: [PATCH] feat: Work on credential conversion methods Signed-off-by: artem.ivanov --- docs/design/w3c/spec.md | 35 ++- docs/design/w3c/w3c-representation.md | 295 ++++++++++++++++---------- 2 files changed, 211 insertions(+), 119 deletions(-) diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md index e5f20949..9cd9502e 100644 --- a/docs/design/w3c/spec.md +++ b/docs/design/w3c/spec.md @@ -174,7 +174,8 @@ schema in order to include the information about Indy related definitions to cre * `schema` - id of Indy Schema * `definition` - id of Indy Credential Definition -* `revocation` - id of Indy Revocation Registry +* `revocation` - Revocation Registry Accumulator value +* `witness` - Witness value * `encoding` - attributes encoding algorithm * encoded credential attribute values (binary representation required for doing CL signatures) are not included neither to `credentialSubject` or `signature` @@ -188,8 +189,7 @@ W3C [Issuer](https://www.w3.org/TR/vc-data-model/#issuer) section requires inclu issuer of a verifiable credential. In the case of W3C AnonCreds credentials, the `issuer` attribute should be represented as a -resolvable [DID URL](https://w3c-ccg.github.io/did-resolution/) having either `indy` or `sov` DID method and looks the -following: +resolvable [DID URL](https://w3c-ccg.github.io/did-resolution/) and looks the following: ``` { @@ -252,7 +252,9 @@ entry: ``` { "signature": {..}, - "signature_correctness_proof": {..} + "signature_correctness_proof": {..}, + "rev_reg": Option<{..}>, + "witness": Option<{..}>, } ``` * encoded @@ -482,12 +484,25 @@ type pointing to the difference in a presentation structure and looks the follow type) -* **TO DISCUSS**: Should we derive an attribute from a predicate and put them into credentialSubject like it demonstrated - in the [specification](https://www.w3.org/TR/vc-data-model/#presentations-using-derived-credentials) - * Example: - * For Predicate: `{"name": "birthdate", "p_type": "<", "value":"20041012"}` - * Derived attribute: `{"birthdate": "birthdate less 20041012"}` - * During the `proofValue` crypto verification we can parse the phrase and restore predicate attributes +* **TO DISCUSS**: Predicates representation in credential subject + * Derive an attribute and put it into `credentialSubject` like it demonstrated + in the [specification](https://www.w3.org/TR/vc-data-model/#presentations-using-derived-credentials) + * Example: + * For Predicate: `{"name": "birthdate", "p_type": "<", "value":"20041012"}` + * Derived attribute: `{"birthdate": "birthdate less 20041012"}` + * During the `proofValue` crypto verification we can parse the phrase and restore predicate attributes + * Put predicate as object into `credentialSubject` + ``` + "credentialSubject": { + ... + "birthdate": { + "type": "Predicate", + "p_type": "<", + "value": "20041012" + } + ... + } + ``` #### Proof diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 4c3d252e..5224ab47 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -1,71 +1,91 @@ ## Design for W3C representation of AnonCreds credentials and presentation -Currently `anoncreds-rs` library only provides support for Indy styled AnonCreds credentials matching to the [specification](https://hyperledger.github.io/anoncreds-spec/). +Currently `anoncreds-rs` library only provides support for Indy styled AnonCreds credentials matching to +the [specification](https://hyperledger.github.io/anoncreds-spec/). -This design document proposes extending of `anoncreds-rs` library to add support for AnonCreds W3C representation of verifiable credential and presentation described in the [document](). +This design document proposes extending of `anoncreds-rs` library to add support for AnonCreds W3C representation of +verifiable credential and presentation described in the [document](). ### Goals and ideas * Use Indy styled credentials to generate W3C AnonCreds credentials and presentations - * Credentials conversion: - * Convert Indy styled AnonCreds credentials into W3C form - * Convert W3C styled AnonCreds credentials into Indy form - * Presentation conversion (Optional): - * Convert Indy styled AnonCreds presentation into W3C form - * Convert W3C styled AnonCreds presentation into Indy form -* Extend W3C credentials: - * Ability to set Data Integrity proof signatures for generated W3C credential objects: - * W3C credentials may contain multiple signatures - * AnonCreds-Rs only generates/handle AnonCreds signatures + * Credentials conversion: + * Convert Indy styled AnonCreds credentials into W3C form + * Convert W3C styled AnonCreds credentials into Indy form + * Presentation conversion (Optional): + * Convert Indy styled AnonCreds presentation into W3C form + * Convert W3C styled AnonCreds presentation into Indy form +* Extend W3C credentials: + * Ability to set Data Integrity proof signatures for generated W3C credential objects: + * W3C credentials may contain multiple signatures + * AnonCreds-Rs only generates/handle AnonCreds signatures #### Out of scope * Credentials: Verify validity of the Data Integrity proof signature * Presentations: Create presentation using Data Integrity proof signature -* Presentations: Verify validity of presentations using Data Integrity proof signatures +* Presentations: Verify validity of presentations using Data Integrity proof signatures * Presentations: Support different formats (for example DIF) of Presentation Request ### Question impacting the approach * Q1: Do we need conversion for intermediate messages to make them W3C compliant: Credential Offer, Credential Request? - * Q1.1: (Depends on answer for Q1) If no conversion: Do we want Credential Offer indicates what form of credential will be issued as the process execution result? -* Q2: Do we want duplicate methods (like `sign` and `sign_w3c`) or only use single conversion method (like `credential.to_w3c`) doing extra step? -* Q3: Should we care about the legacy credential migration and compatibility? Or achieve better following to the W3C standard with preserving power of CL signatures? - * example pros of dropping legacy support: - * different attributes types can be used in credentialSubject (support nested objects, array, other features) - * Need to decide on object encoding algorithm - * attributes mapping in presentation request can be simplified but with loosing ability to make back conversion -* Q4: Are we still tied to Indy styled presentation request? - * Q4.1: (Depends on answer for Q3) If yes: Do we want Presentation Request indicates what form of presentation need to be created (`PresentationRequestV3`)? - * Q4.2: (Depends on answer for Q3) If no: What Presentation Request format need to be supported? DIF? -* Q5: Do we want to provide general interfaces doing signing and verification of Data Integrity proof signature? - * Accept sign/verify callbacks into convert functions: - * Issue with setting multiple signatures - * Much easier just to expose methods to add signature proof itself -* Q6: Signature/Proof encoding: Which approach to use for encoding? - * Basic approach used in Aries attachments - Base 64 encoding of serialized object (`base64(json(signature).as_bytes())`) ? - * Compact encoding implementing in Python PoC? + * Q1.1: (Depends on answer for Q1) If no conversion: Do we want Credential Offer indicates what form of credential + will be issued as the process execution result? + * Proposed answer: no conversion for the current phase +* Q2: Do we want duplicate methods (like `sign` and `sign_w3c`) or only use single conversion method ( + like `credential.to_w3c`) doing extra step? + * There are 6 methods in total. 4 of them we have to duplicate any way. Whether we want to + duplicate `create_offer`, `create_request` methods if we do not change their format. + * Proposed answer: yes - duplicate all methods +* Q3: Are we still tied to Indy styled presentation request? + * Can we make interface completely independent of Presentation Request? So any form can be handled on top level and + specific data passed to AnonCreds-rs. + * Proposed answer: Make AnonCreds-rs methods presentation agnostic. +* Q4: Do we want to provide general interfaces doing signing and verification of Data Integrity proof signature? + * Accept sign/verify callbacks into convert/create functions: + * Issue with setting multiple signatures + * Much easier just to expose methods to add signature proof itself + * Provide methods to put ready data into a credential + * Proposed answer: delegate to third party libraries using `anoncreds-rs` +* Q5: Signature/Proof encoding: Which approach to use for encoding? + * Basic approach used in Aries attachments - Base 64 encoding of serialized + object (`base64(json(signature).as_bytes())`) ? + * Compact encoding implementing in Python PoC? + * Proposed answer: Start from basic approach? +* Q6: Should we care about back way conversion of credential issued in W3C form? + * Assume that we issued W3C which cannot convert back into Indy form + * For example supporting different attributes types can be used in credentialSubject (support nested objects, array, + other features) + * Need to decide on object encoding algorithm ### Proposed implementation path for first iteration 1. Credential conversion APIs -2. Credential methods (set_integrity_proof, get_signing_payload?, etc?) - do not care about Data Integrity proof signatures +2. Credential helper methods for integrity proof handling (set_integrity_proof, get_signing_payload?, etc?) + * Generation and verification of Data Integrity proof signature are done by third party libraries using `anoncreds-rs` + * `anoncreds-rs` only provides methods to put ready data into a credential 3. Flow duplication APIs -4. Adopt Credential Offer and Credential Request for W3C standard ???? -5. Support only Indy presentation request type (for the first iteration) +4. Adopt Credential Offer and Credential Request for W3C standard - No + * It's not clear. W3C provides format of Credential and Presentation but not intermediate protocol messages + * OpenID4VC - do they have intermediate messages (Credential Offer)? +5. Make presentation request agnostic API ### Public API #### Credential/Presentation Conversion methods The idea for this approach is only provide conversion method for credentials and presentations. -So credentials and presentations themselves are generate the same way and the same functions as before but if W3C form is require application uses conversion methods to get required format. +So credentials and presentations themselves are generate the same way and the same functions as before but if W3C form +is require application uses conversion methods to get required format. #### Credential Conversion methods -These methods allow to solve both cases: -* Use old Indy styled credentials issued before -* Issuing new credentials in W3C form +These methods allow to solve both cases: + +Methods purpose - have to forms of credentials (probably even duplicate in wallet) to cover both cases: Indy and W3C +* `anoncreds_credential_to_w3c` - create W3C Presentation using a credential previously issued in Indy form +* `anoncreds_credential_from_w3c` - create an Indy-styled presentation (for legacy Verifier) using a credential issued in W3C form ```rust /// Convert Indy styled AnonCreds credential into W3C AnonCreds credential form @@ -85,7 +105,7 @@ pub extern "C" fn anoncreds_credential_to_w3c( /// Convert W3C styled AnonCreds credential into Indy styled credential /// The conversion process described at the specification: --- -/// +/// /// # Params /// cred - object handle pointing to W3C styled AnonCreds credential to convert /// cred_p - reference that will contain converted credential (in Indy form) instance pointer @@ -112,8 +132,8 @@ pub extern "C" fn anoncreds_credential_from_w3c( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_credential_get_signing_payload( - cred: ObjectHandle, - signing_payload_p: *mut *const c_char, + cred: ObjectHandle, + signing_payload_p: *mut *const c_char, ) -> ErrorCode {} /// Set Data Integrity proof signature for W3C AnonCreds credential @@ -126,15 +146,17 @@ pub extern "C" fn anoncreds_w3c_credential_get_signing_payload( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_credential_set_integrity_proof( - cred: ObjectHandle, - proof: FfiStr, + cred: ObjectHandle, + proof: FfiStr, ) -> ErrorCode {} ``` #### Optional: Presentation Conversion methods -Presentation conversion methods are only required if we decide not to implement duplication flow methods even for presentation exchange. -In this case, library will provide APIs to create/verify Indy formatted presentation and APIs to convert it into/from W3C form. +Presentation conversion methods are only required if we decide not to implement duplication flow methods even for +presentation exchange. +In this case, library will provide APIs to create/verify Indy formatted presentation and APIs to convert it into/from +W3C form to support different Verifiers. ```rust /// Convert Indy styled AnonCreds presentation into W3C AnonCreds presentation form @@ -173,22 +195,31 @@ pub extern "C" fn anoncreds_presentation_from_w3c( The idea for this approach to duplicate all issuance/presentation related methods for w3c standard. So the credentials and presentations themselves are generated using new flow methods. -> Note, that we still need to implement credential conversion methods to support the case of using existing/issued credentials for doing the w3c presentation. -> Firstly, old credentials should be converted into a W3C form, and the next new presentation creation method can be used. + +> Note, that we still need to implement credential conversion methods to support the case of using existing/issued +> credentials for doing the w3c presentation. +> Firstly, old credentials should be converted into a W3C form, and the next new presentation creation method can be +> used. + +In fact, there are 6 main flow methods in total. +4 of them we have to duplicate: `create_credential`, `process_credential`, `create_presentation`, `verify_presentation`. +Whether we want to duplicate `create_offer`, `create_request` methods if we do not change their format? The reasons for adding duplication methods: -- avoid breaking changes in the existing API - - for example if we want Credential Offer pointing to the form of a credential to be issued -- clear separation between flows - - if a flow targeting issuing of W3C Credential the specific set of function to be used + +- avoid breaking changes in the existing API + - for example if we want Credential Offer pointing to the form of a credential to be issued +- clear separation between flows + - if a flow targeting issuing of W3C Credential the specific set of function to be used - avoid the situation when function result value may be in different forms - - example: - - issuer creates offer in Indy form but with indy or w3c indication - - as the flow execution result, create credential function returns credential either in w3c or indy form depending on offer - - if application analyze credential somehow it cause difficulties + - example: + - issuer creates offer in Indy form but with indy or w3c indication + - as the flow execution result, create credential function returns credential either in w3c or indy form + depending on offer + - if application analyze credential somehow it cause difficulties - easier deprecation of indy styled credentials and APIs - presentation conversion methods are not needed anymore in this case - - only credential conversion method to do migration for previously issued credentials + - only credential conversion method to do migration for previously issued credentials > We can do only part of the work: add duplication methods for presentation but leave old methods for credentials @@ -198,9 +229,9 @@ The reasons for adding duplication methods: /// If Indy styled credential to be used, it should indicate that credential in W3C AnonCreds form will be issued as the result. /// /// TO DISCUSS: Should we convert/adopt Credential Offer for W3C form? -/// +/// /// Even if we do not change Credential Offer message itself we start from using a separate set of API functions -/// +/// /// # Params /// schema_id: id of schema future credential refers to /// cred_def_id: id of credential definition future credential refers to @@ -211,10 +242,10 @@ The reasons for adding duplication methods: /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_create_credential_offer( - schema_id: FfiStr, - cred_def_id: FfiStr, - key_proof: ObjectHandle, - cred_offer_p: *mut ObjectHandle, + schema_id: FfiStr, + cred_def_id: FfiStr, + key_proof: ObjectHandle, + cred_offer_p: *mut ObjectHandle, ) -> ErrorCode {} /// Create Credential Request according to the AnonCreds specification @@ -224,7 +255,7 @@ pub extern "C" fn anoncreds_w3c_create_credential_offer( /// TO DISCUSS: Should we convert/adopt Credential Request for W3C form? /// /// Even if we do not change Credential Request message itself we start from using a separate set of API functions -/// +/// /// # Params /// entropy: entropy string to use for request creation /// prover_did: DID of the credential holder @@ -239,14 +270,14 @@ pub extern "C" fn anoncreds_w3c_create_credential_offer( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_create_credential_request( - entropy: FfiStr, - prover_did: FfiStr, - cred_def: ObjectHandle, - link_secret: FfiStr, - link_secret_id: FfiStr, - cred_offer: ObjectHandle, - cred_req_p: *mut ObjectHandle, - cred_req_meta_p: *mut ObjectHandle, + entropy: FfiStr, + prover_did: FfiStr, + cred_def: ObjectHandle, + link_secret: FfiStr, + link_secret_id: FfiStr, + cred_offer: ObjectHandle, + cred_req_p: *mut ObjectHandle, + cred_req_meta_p: *mut ObjectHandle, ) -> ErrorCode {} /// Create W3C styled Credential according to the specification. @@ -265,14 +296,14 @@ pub extern "C" fn anoncreds_w3c_create_credential_request( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_create_credential( - cred_def: ObjectHandle, - cred_def_private: ObjectHandle, - cred_offer: ObjectHandle, - cred_request: ObjectHandle, - attr_names: FfiStrList, - attr_raw_values: FfiStrList, - revocation: *const FfiCredRevInfo, - cred_p: *mut ObjectHandle, + cred_def: ObjectHandle, + cred_def_private: ObjectHandle, + cred_offer: ObjectHandle, + cred_request: ObjectHandle, + attr_names: FfiStrList, + attr_raw_values: FfiStrList, + revocation: *const FfiCredRevInfo, + cred_p: *mut ObjectHandle, ) -> ErrorCode {} /// Process an incoming W3C credential received from the issuer. @@ -291,12 +322,12 @@ pub extern "C" fn anoncreds_w3c_create_credential( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_process_credential( - cred: ObjectHandle, - cred_req_metadata: ObjectHandle, - link_secret: FfiStr, - cred_def: ObjectHandle, - rev_reg_def: ObjectHandle, - cred_p: *mut ObjectHandle, + cred: ObjectHandle, + cred_req_metadata: ObjectHandle, + link_secret: FfiStr, + cred_def: ObjectHandle, + rev_reg_def: ObjectHandle, + cred_p: *mut ObjectHandle, ) -> ErrorCode {} /// Get value of request credential attribute as string @@ -310,9 +341,9 @@ pub extern "C" fn anoncreds_w3c_process_credential( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_credential_get_attribute( - handle: ObjectHandle, - name: FfiStr, - result_p: *mut *const c_char, + handle: ObjectHandle, + name: FfiStr, + result_p: *mut *const c_char, ) -> ErrorCode {} /// Create W3C styled Presentation according to the specification. @@ -334,17 +365,16 @@ pub extern "C" fn anoncreds_w3c_credential_get_attribute( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_create_presentation( - pres_req: ObjectHandle, - credentials: FfiList, - credentials_prove: FfiList, - self_attest_names: FfiStrList, - self_attest_values: FfiStrList, - link_secret: FfiStr, - schemas: FfiList, - schema_ids: FfiStrList, - cred_defs: FfiList, - cred_def_ids: FfiStrList, - presentation_p: *mut ObjectHandle, + credentials: FfiList, + credentials_prove: FfiList, + self_attest_names: FfiStrList, + self_attest_values: FfiStrList, + link_secret: FfiStr, + schemas: FfiList, + schema_ids: FfiStrList, + cred_defs: FfiList, + cred_def_ids: FfiStrList, + presentation_p: *mut ObjectHandle, ) -> ErrorCode {} /// Create W3C styled Presentation according to the specification. @@ -366,17 +396,17 @@ pub extern "C" fn anoncreds_w3c_create_presentation( /// Error code #[no_mangle] pub extern "C" fn anoncreds_w3c_verify_presentation( - presentation: ObjectHandle, - pres_req: ObjectHandle, - schemas: FfiList, - schema_ids: FfiStrList, - cred_defs: FfiList, - cred_def_ids: FfiStrList, - rev_reg_defs: FfiList, - rev_reg_def_ids: FfiStrList, - rev_status_list: FfiList, - nonrevoked_interval_override: FfiList, - result_p: *mut i8, + presentation: ObjectHandle, + pres_req: ObjectHandle, + schemas: FfiList, + schema_ids: FfiStrList, + cred_defs: FfiList, + cred_def_ids: FfiStrList, + rev_reg_defs: FfiList, + rev_reg_def_ids: FfiStrList, + rev_status_list: FfiList, + nonrevoked_interval_override: FfiList, + result_p: *mut i8, ) -> ErrorCode {} ``` @@ -385,3 +415,50 @@ pub extern "C" fn anoncreds_w3c_verify_presentation( Methods similar to Credential / Presentation conversion into W3C format. > Do not see a sense + +### Demo scripts + +> IN PROGRESS + +#### Issue Indy Credential and present W3C Presentation + +``` +indy_credential_offer = Issuer.anoncreds_create_credential_offer(...) +indy_credential_request = Holder.anoncreds_create_credential_request(indy_credential_offer,...) +indy_credential = Issuer.anoncreds_create_credential(indy_credential_request,...) +indy_credential = Holder.anoncreds_process_credential(indy_credential,...) + +w3c_credential = Holder.anoncreds_credential_to_w3c(indy_credential) + +w3c_presentation_request = Verifier.anoncreds_w3c_create_presentation_request() +w3c_presentation = Holder.anoncreds_w3c_create_presentation(w3c_presentation_request, w3c_credential) +Verifier.anoncreds_w3c_verify_presentation(w3c_presentation) +``` + +#### Issue W3C Credential and present Indy Presentation + +``` +w3c_credential_offer = Issuer.anoncreds_w3c_create_credential_offer(...) +w3c_credential_request = Holder.anoncreds_w3c_create_credential_request(w3c_credential_offer,...) +w3c_credential = Issuer.anoncreds_w3c_create_credential(w3c_credential_request,...) +w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...) + +indy_credential = Holder.anoncreds_credential_from_w3c(w3c_credential) + +indy_presentation_request = Verifier.create_presentation_request() +indy_presentation = Holder.create_presentation(indy_presentation_request, indy_credential) +Verifier.anoncreds_verify_presentation(indy_presentation) +``` + +#### Issue W3C Credential and present W3C Presentation + +``` +w3c_credential_offer = Issuer.anoncreds_w3c_create_credential_offer(...) +w3c_credential_request = Holder.anoncreds_w3c_create_credential_request(w3c_credential_offer,...) +w3c_credential = Issuer.anoncreds_w3c_create_credential(w3c_credential_request,...) +w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...) + +w3c_presentation_request = Verifier.anoncreds_w3c_create_presentation_request() +w3c_presentation = Holder.anoncreds_w3c_create_presentation(w3c_presentation_request, w3c_credential) +Verifier.anoncreds_w3c_verify_presentation(w3c_presentation) +``` \ No newline at end of file