From 3df1bc9c6540da1ed5ed19b066a2b8d615a89aa1 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Thu, 2 Nov 2023 17:28:38 +0300 Subject: [PATCH 01/13] design: Added initial versions for spec and API documents Signed-off-by: artem.ivanov --- docs/design/w3c/context.json | 84 ++++ docs/design/w3c/encoding.md | 113 ++++++ docs/design/w3c/spec.md | 530 ++++++++++++++++++++++++++ docs/design/w3c/w3c-representation.md | 387 +++++++++++++++++++ 4 files changed, 1114 insertions(+) create mode 100644 docs/design/w3c/context.json create mode 100644 docs/design/w3c/encoding.md create mode 100644 docs/design/w3c/spec.md create mode 100644 docs/design/w3c/w3c-representation.md diff --git a/docs/design/w3c/context.json b/docs/design/w3c/context.json new file mode 100644 index 00000000..ce254499 --- /dev/null +++ b/docs/design/w3c/context.json @@ -0,0 +1,84 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "ac": "https://anoncreds.example/2022/ns#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "AnonCredsCredential": "ac:AnonCredsCredential", + + "AnonCredsDefinition": { + "@id": "ac:AnonCredsDefinition", + "@context": { + "@version": 1.1, + "@protected": true, + "definition": { + "@id": "ac:definition", + "@type": "@id" + }, + "schema": { + "@id": "ac:schema", + "@type": "@id" + }, + "revocation": { + "@id": "ac:revocation", + "@type": "@id" + }, + "encoding": { + "@id": "ac:attributeEncoding", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + "auto": "ac:autoEncoding" + } + } + } + }, + + "AnonCredsPresentation": "ac:AnonCredsPresentation", + + "AnonCredsPresentationProof2022": { + "@id": "ac:AnonCredsPresentationProof2022", + "@context": { + "@version": 1.1, + "@protected": true, + "credential": { + "@id": "ac:credentialProof", + "@context": { + "@version": 1.1, + "@protected": true, + "mapping": { + "@id": "ac:attributeMapping", + "@type": "@json" + }, + "proofValue": { + "@id": "ac:proofValue", + "@type": "xsd:string" + } + } + }, + "proofValue": { + "@id": "ac:proofValue", + "@type": "xsd:string" + }, + "challenge": { + "@id": "ac:challenge", + "@type": "xsd:string" + } + } + }, + + "CLSignature2023": { + "@id": "ac:CLSignature2023", + "@context": { + "@version": 1.1, + "@protected": true, + "signature": { + "@id": "ac:signature", + "@type": "xsd:string" + } + } + } + } +} diff --git a/docs/design/w3c/encoding.md b/docs/design/w3c/encoding.md new file mode 100644 index 00000000..5367fba3 --- /dev/null +++ b/docs/design/w3c/encoding.md @@ -0,0 +1,113 @@ +### Encoding + +As all fields of AnonCreds credential signature and proof objects are big numbers, the straight object JSON serialization and representing as bytes is not effective. +Instead, we propose using of an alternative algorithm, providing more compact representation, consisting of the following steps: + +Also, due to the fact that fields order matters during serialization/deserialization process, encoding must be applied to attributes in alphabetic order. + +> TO DISCUSS: For simplicity we still can use straight object JSON serialization and representing as bytes but the size of encoded string will be almost 3 times bigger. + +##### Encoding steps + +1. Iterate over object `attributes` +2. Get **size** (`number bytes`) required for each attribute value (`BigNumber`) and **value as bytes** (big-endian) +3. Append `number bytes` (reserve 2 bytes for it) and `value as bytes` to resulting array +4. After adding all attributes encode the resulting bytes array as base64 string + +**Value encoding rules:** +* BigNumber: get value size and bytes +* Nested object: apply the same steps to encode itself as bytes +* Array: get count of elements and encode each element +* Optional values: use zero as size and empty array for value +* Map: encode key and value as usual + +##### Decoding steps + +1. Read 2 bytes corresponding to the attribute value size +2. Read next N bytes corresponding to the value size +3. Restore value from bytes +4. Repeat the process for the tail + +#### Credential Signature encoding + +Fields order: +* `Signature: `[signature, signature_correctness_proof] +* `CredentialSignature: `[a, e, m_2, v]` +* `SignatureCorrectnessProof: `[c, se]` + +```rust +/// Need to construct an object containing CredentialSignature and SignatureCorrectnessProof +struct Signature { + signature: CredentialSignature, + signature_correctness_proof: SignatureCorrectnessProof, +} + +/// Encoding fields order: [signature, signature_correctness_proof] +impl Signature { + fn to_bytes(&self) -> Vec { + let (signature_size, signature_bytes) = self.signature.get_size_and_bytes(); + let (signature_correctness_proof_size, signature_correctness_proof_bytes) = self.signature_correctness_proof.get_size_and_bytes(); + vec![ + ..signature_size, + ..signature_bytes, + ..signature_correctness_proof_size, + ..signature_correctness_proof_bytes, + ] + } + + fn from_bytes(bytes: &[u8]) -> SignatureCorrectnessProof { + // set start and end + let signature: CredentialSignature = CredentialSignature::from_bytes(&bytes[start..end]); + // change start and end + let signature_correctness_proof: SignatureCorrectnessProof = SignatureCorrectnessProof::from_bytes(&bytes[start..end]); + Signature { + signature, + signature_correctness_proof, + } + } +} + +/// Similar implementation for `CredentialSignature` and `SignatureCorrectnessProof` objects +``` + +#### Presentation Proof encoding + +Fields coder: +* `SubProof: `[non_revoc_proof, primary_proof] +* `PrimaryProof: `[eq_proof, ge_proofs]` + * because `ge_proofs` is an array we need to append elements count into the resulting array +* `NonRevocProof: `[c_list, x_list]` + +```rust +/// Need to construct an object containing CredentialSignature and SignatureCorrectnessProof +struct SubProof { + primary_proof: PrimaryProof, + non_revoc_proof: Option, +} + +/// Encoding fields order: [non_revoc_proof, primary_proof] +impl SubProof { + fn to_bytes(&self) -> Vec { + // use `0` for `non_revoc_proof_size` and empty array for `non_revoc_proof_bytes` (all Optional fields) + let (non_revoc_proof_size, non_revoc_proof_bytes) = self.non_revoc_proof.get_size_and_bytes(); + let (primary_proof_size, non_revoc_proof_bytes) = self.non_revoc_proof.get_size_and_bytes(); + vec![ + ..non_revoc_proof_size, + ..non_revoc_proof_bytes, + ..primary_proof_size, + ..non_revoc_proof_bytes, + ] + } + + fn from_bytes(bytes: &[u8]) -> SignatureCorrectnessProof { + // set start and end + let non_revoc_proof: NonRevocProof = NonRevocProof::from_bytes(&bytes[start..end]); + // change start and end + let primary_proof: PrimaryProof = PrimaryProof::from_bytes(&bytes[start..end]); + SubProof { + non_revoc_proof, + primary_proof, + } + } +} +``` \ No newline at end of file diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md new file mode 100644 index 00000000..e5f20949 --- /dev/null +++ b/docs/design/w3c/spec.md @@ -0,0 +1,530 @@ +## W3C Verifiable Credentials Representation + +This section describes how Indy-styled AnonCreds credentials can be represented in the form of W3C Verifiable +Credentials standard. + +### Credential + +This section describes how [W3C credential concepts](https://www.w3.org/TR/vc-data-model/#basic-concepts) are applied to +AnonCreds W3C credential representation. + +Example of an AnonCreds W3C formatted credential which will be explained in details: + +```json +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://github.io/anoncreds-w3c/context.json" + ], + "type": [ + "VerifiableCredential", + "AnonCredsCredential" + ], + "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", + "issuanceDate": "2023-10-26T01:17:32Z", + "credentialSchema": { + "type": "AnonCredsDefinition", + "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", + "encoding": "auto" + }, + "credentialSubject": { + "firstName": "Alice", + "lastName": "Jones", + "age": "18" + }, + "proof": [ + { + "type": "CLSignature2023", + "signature": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM" + }, + { + "type": "Ed25519Signature2020", + "created": "2021-11-13T18:19:39Z", + "verificationMethod": "did:sov:3avoBCqDMFHFaKUHug9s8W#key-1", + "proofPurpose": "assertionMethod", + "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" + } + ] +} +``` + +#### Context + +W3C [Context](https://www.w3.org/TR/vc-data-model/#contexts) section requires including of `@context` property to +verifiable credential. + +The value of the `@context` property must be one or more resolvable [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) +that result in machine-readable [JSON-LD](https://www.w3.org/TR/vc-data-model/#json-ld) information about the object +format. + +The **context** definition used for AnonCreds W3C credentials representation can be found [here](./context.json). + +In the case of W3C AnonCreds credentials, the `@context` attribute includes an extra +entry `https://github.io/anoncreds-w3c/context.json` +which is required for the resolution of custom structure definitions and looks the following: + +``` +{ + ... + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://github.io/anoncreds-w3c/context.json" + ], + ... +} +``` + +#### Identifiers + +W3C [Identifiers](https://www.w3.org/TR/vc-data-model/#identifiers) section defines an optional capability to assign +some kind of identifier to the verifiable credential so that others can express statements about the same thing. + +In the case of W3C AnonCreds credentials, the `id` attribute is not recommended to set. + +#### Types + +W3C [Types](https://www.w3.org/TR/vc-data-model/#types) section requires including of `type` property to verifiable +credential. +The value of the `type` property must be one or more [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) resolvable +through the defined `@context` to the information required for determining whether a verifiable credential or verifiable +presentation has a valid structure. + +In the case of W3C AnonCreds credentials, the `type` attribute includes an extra entry `AnonCredsCredential` +pointing to the difference in a base credential structure and looks the following: + +``` +{ + ... + "type": [ + "VerifiableCredential", // general verifiable credential definition + "AnonCredsCredential", // definition for AnonCreds credentials + ] + ... +} +``` + +#### Credential Subject + +W3C [Credential Subject](https://www.w3.org/TR/vc-data-model/#credential-subject) section requires including +of `credentialSubject` property to verifiable credential. + +Credential subject value contains [claims](https://www.w3.org/TR/vc-data-model/#claims) about one or more subjects. + +In the context of W3C Announced credentials, credential subject property is compliant with the following statements: + +- credentials will always include claims about only one subjects. + - So that `credentialSubject` property will always be represented as an object entry, but not an array. +- credentials claims are always represented as key value pairs, where `value` is the `raw` value of CL credential + attributes. + - encoded CL credential values are not included in the credential subject + +In the case of W3C AnonCreds credentials, the `credentialSubject` attribute looks the following: + +``` +{ + ... + "credentialSubject": { + "name": "Alice Jones", + } + ... +} +``` + +* **TO DISCUSS**: W3C data model allows attributes to be represented not only as key/value string pairs but also as + objects and arrays. + * If we want to support more complex representations for the W3C AnonCreds credential attributes and their + presentations, we need to design following things: + * how encoding will work for such attributes + * how selective disclosure will work on top level attribute itself + ``` + "credentialSubject": { + "address": { + "type": "Address", + "city": "Foo", + "street": "Main str." + } + } + ``` + +#### Data Schemas + +W3C [Credential Subject](https://www.w3.org/TR/vc-data-model/#data-schemas) section defines an optional capability to +include `credentialSchema` property to enforce a specific structure on a given verifiable credential and encoding used +to map the claims of a verifiable credential to an alternative representation format. + +In the context of W3C AnonCreds credentials defined a custom `AnonCredsDefinition` data schema in order to include the +following information to credential: + +In the case of W3C AnonCreds credentials, the `credentialSchema` attribute defines a custom `AnonCredsDefinition` +schema in order to include the information about Indy related definitions to credential and looks the following: + +``` +{ + ... + "credentialSchema": { + "type": "AnonCredsDefinition", + "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:fabername:0.1.0", + "encoding": "auto" + }, + ... +} +``` + +* `schema` - id of Indy Schema +* `definition` - id of Indy Credential Definition +* `revocation` - id of Indy Revocation Registry +* `encoding` - attributes encoding algorithm + * encoded credential attribute values (binary representation required for doing CL signatures) are not included + neither to `credentialSubject` or `signature` + * `encoding: auto` implies using the algorithm defined + at [Aries RFC 0592 Indy Attachments section](https://github.com/hyperledger/aries-rfcs/tree/main/features/0592-indy-attachments#encoding-claims) + to generate encoded values under the hood during the signature generation and proof verification. + +#### Issuer + +W3C [Issuer](https://www.w3.org/TR/vc-data-model/#issuer) section requires including of `issuer` property to express the +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: + +``` +{ + ... + "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", + ... +} +``` + +#### Issuance Date + +W3C [Issuance Date](https://www.w3.org/TR/vc-data-model/#issuance-date) section requires including of `issuanceDate` +property to express the date and time when a credential becomes valid. + +In the case of W3C AnonCreds credentials, for the `issuanceDate` attribute recommended setting of a random time of the +day when credential was issued or transformed and looks the following: + +``` +{ + ... + "issuanceDate": "2010-01-01T19:23:24Z", + ... +} +``` + +#### Proofs (Signatures) + +W3C [Proofs (Signatures)](https://www.w3.org/TR/vc-data-model/#proofs-signatures) section requires including of `proof` +property to express confirmation of the credential's validity. + +According to the specification, one or many proof objects can be added to verifiable credentials. +In the context of W3C AnonCreds credentials included at least two proof object entries: AnonCreds CL +and [Data Integrity](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs). + +##### AnonCreds CL proof + +This proof entry derived from the CL signature of a verifiable credential. + +The defined `@context` includes a definition for the `CLSignature2022` type describing the format of the proof +entry: + +``` +{ + ... + "proof": [ + { + "type": "CLSignature2022", + "signature": "AAAgf9w5lZg....RYp8Z_x3FqdwRHoWruiF0FlM" + } + ] + ... +} +``` + +**Credential proof signature** + +* `type` - `CLSignature2022` +* `signature` - credential signature + * signature received by building the following object from indy styled credential: + ``` + { + "signature": {..}, + "signature_correctness_proof": {..} + } + ``` + * encoded + as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url) + + +* **TO DISCUSS**: Signature/Proof encoding: Which approach to use for encoding? + * Basic approach used in Aries attachments: Base 64 encoding of object serialized as JSON string + * Compact encoding implementing in Python PoC: Using the fact that most fields of credential signature and proof are big numbers + +##### Data Integrity proof + +In order to better conform to the W3C specification AnonCreds based credential also requires including +of [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs) which must be generated using one +of NIST-approved algorithms (RSA, ECDSA, EdDSA). + +Including Data Integrity proof allows to use verifiable credential without access to a Ledger. + +#### Expiration + +W3C [Expiration](https://www.w3.org/TR/vc-data-model/#expiration) section defines an optional capability to include +credential expiration information. + +Instead of including `expirationDate` property we recommend using a standard indy credentials revocation approach and +include a revocation registry id into the credential schema. + +#### Status + +W3C [Status](https://www.w3.org/TR/vc-data-model/#status) section defines an optional capability to include credential +status information. + +Instead of including `credentialStatus` property we recommend using a standard indy credentials revocation approach and +include a revocation registry id into the credential schema. + +### Presentation + +This section describes how [W3C presentation concepts](https://www.w3.org/TR/vc-data-model/#contexts) are applied to +AnonCreds +W3C presentation representation. + +Example of an AnonCreds W3C presentation which will be explained in details: + +```json +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://github.io/anoncreds-w3c/context.json" + ], + "type": [ + "VerifiablePresentation", + "AnonCredsPresentation" + ], + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://github.io/anoncreds-w3c/context.json" + ], + "type": [ + "VerifiableCredential", + "AnonCredsPresentation" + ], + "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", + "issuanceDate": "2023-10-26T01:17:32Z", + "credentialSchema": { + "type": "AnonCredsDefinition", + "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", + "encoding": "auto" + }, + "credentialSubject": { + "firstName": "Alice" + }, + "proof": { + "type": "AnonCredsPresentationProof2022", + "credential": { + "mapping": { + "revealedAttributes": [ + { + "name": "firstName", + "referent": "attribute_0" + } + ], + "unrevealedAttributes": [ + { + "name": "lastName", + "referent": "attribute_1" + } + ], + "requestedPredicates": [ + { + "name": "age", + "p_type": "<", + "value": 18, + "referent": "predicate_1" + } + ] + }, + "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" + } + } + } + ], + "proof": { + "type": "AnonCredsPresentationProof2022", + "challenge": "182453895158932070575246", + "proofValue": "AAAgtMR4....J19l-agSA" + } +} +``` + +#### Context + +W3C [Context](https://www.w3.org/TR/vc-data-model/#contexts) section requires including of `@context` property to +verifiable presentation. +The value of the `@context` property must be one or more resolvable [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) +that result in machine-readable [JSON-LD](https://www.w3.org/TR/vc-data-model/#json-ld) information about the object +format. + +The complete **context** containing definitions used for AnonCreds W3C credentials representation can be +found [here](./context.json). + +In the case of W3C AnonCreds presentations, the `@context` attribute includes an extra +entry `https://github.io/anoncreds-w3c/context.json` +which is required for the resolution of custom structure definitions and looks the following: + +``` +{ + ... + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://github.io/anoncreds-w3c/context.json" + ], + ... +} +``` + +#### Types + +W3C [Types](https://www.w3.org/TR/vc-data-model/#types) section requires including of `type` property to verifiable +presentation. +The value of the `type` property must be one or more [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) resolvable +through the defined `@context` to the information required for determining whether a verifiable +presentation has a valid structure. + +In the case of W3C AnonCreds presentations, the `type` attribute includes an extra entry `AnonCredsPresentation` +pointing to the difference in a base presentation structure and looks the following: + +``` +{ + ... + "type": [ + "VerifiablePresentation", // general verifiable presentation definition + "AnonCredsPresentation" // definition for AnonCreds presentation + ] + ... +} +``` + +#### Verifiable Credential + +W3C [Verifiable Credential](https://www.w3.org/TR/vc-data-model/#presentations-0)section requires including +of `verifiableCredential` property to a verifiable presentation constructed from one or more verifiable credentials. + +The values of verifiable credentials are mostly constructed the same as described at +the [Credential Structure](#credential) section. +The only difference is the value of the `proof` property. + +In the case of W3C AnonCreds presentations, the `proof` attribute uses defined `AnonCredsPresentationProof2022` +type pointing to the difference in a presentation structure and looks the following: + +``` + "proof": { + "type": "AnonCredsPresentationProof2022", + "credential": { + "mapping": { + "revealedAttributes": [ + { + "name": "firstName", + "referent": "attribute_0" + } + ], + "unrevealedAttributes": [ + { + "name": "lastName", + "referent": "attribute_1" + } + ], + "requestedPredicates": [ + { + "name": "age", + "p_type": "<", + "value": 18, + "referent": "predicate_1" + } + ] + }, + "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" + } + } +``` + +**Verifiable Credential Proof structure** + +* `proofValue` - encoded proof generated for each specific credential + * object created from Indy styled credential sub proof + ``` + { + primaryProof: {..}, + nonRevocProof: {..} + } + ``` + * encoded + as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url). +* `mapping` - date requested in the proof request + * data: attribute name and reference in the proof request + * `revealedAttributes` - list of requested attributes revealed using the credential + * `unrevealedAttributes` - list of requested attributes presented in the credential but left unrevealed + * `requestedPredicates` - list of predicates resolved using the credential + + +* **TO DISCUSS**: Should we remove `mapping` completely or move under encoded `proofValue`? + * Why `mapping` is bad: we make presentation tied to Indy styled Presentation Request + * Mapping is something old indy-fashioned required for validation (not signature verification) that proof matches to + the request itself on the verifier side + * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with + 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 + +#### Proof + +W3C [Proofs (Signatures)](https://www.w3.org/TR/vc-data-model/#proofs-signatures) section requires including of `proof` +property to express confirmation of the presentation's validity. + +As we described in the above section verifiable credentials will contain two proof entries (CL AnonCreds of Data +Integrity). +Unlike verifiable credentials, a presentation can contain only one proof object. + +It is verifier and holder responsibility to negotiate which proof must be used (CL AnonCreds of Data Integrity) in the +presentation: + +* Generate an W3C AnonCreds presentation, with all it’s privacy-preserving power and predicates +* Present the VC using one of Integrity Proof Signatures + +``` +{ + ... + "proof": { + "type": "AnonCredsPresentationProof2022", + "challenge": "182453895158932070575246", + "proofValue": "AAAgtMR4DrkY--ZVgKHmUANE04ET7TzUxZ0vZmVcNt4nCkwBABUACQJ69kJVIxHVAQAIAaJ19l-agSA" + } + ... +} +``` + +**Presentation Proof structure** + +* `challenge` - nonce taken from the presentation request +* `aggregated` - encoded aggregated proof value + * object created from Indy proof data + ``` + { + aggregated: {..}, + } + ``` + * encoded + as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url). diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md new file mode 100644 index 00000000..4c3d252e --- /dev/null +++ b/docs/design/w3c/w3c-representation.md @@ -0,0 +1,387 @@ +## 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/). + +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 + +#### 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: 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? + +### 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 +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) + +### 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. + +#### Credential Conversion methods + +These methods allow to solve both cases: +* Use old Indy styled credentials issued before +* Issuing new credentials in W3C form + +```rust +/// Convert Indy styled AnonCreds credential into W3C AnonCreds credential form +/// The conversion process described at the specification: --- +/// +/// # Params +/// cred - object handle pointing to Indy styled credential to convert +/// cred_p - reference that will contain converted credential (in W3C form) instance pointer +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_credential_to_w3c( + cred: ObjectHandle, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} + +/// 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 +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_credential_from_w3c( + cred: ObjectHandle, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} +``` + +#### Credential object methods + +```rust +/// Get W3C credential payload to sign for making Identity Proof +/// +/// # Params +/// cred - object handle pointing to W3C styled AnonCreds credential +/// signing_payload_p - reference that will contain payload to sign for generation of data integrity proof +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_get_signing_payload( + cred: ObjectHandle, + signing_payload_p: *mut *const c_char, +) -> ErrorCode {} + +/// Set Data Integrity proof signature for W3C AnonCreds credential +/// +/// # Params +/// cred - object handle pointing to W3C styled AnonCreds credential +/// proof - data integrity proof signature as JSON string +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_set_integrity_proof( + 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. + +```rust +/// Convert Indy styled AnonCreds presentation into W3C AnonCreds presentation form +/// The conversion process described at the specification: --- +/// +/// # Params +/// cred - object handle pointing to Indy styled AnonCreds presentation to convert +/// cred_p - reference that will contain converted presentation (in W3C form) instance pointer +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_presentation_to_w3c( + cred: ObjectHandle, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} + +/// Convert W3C styled AnonCreds presentation into Indy styled AnonCreds credential +/// The conversion process described at the specification: --- +/// +/// # Params +/// cred - object handle pointing to W3C styled AnonCreds presentation to convert +/// cred_p - reference that will contain converted presentation (in Indy form) instance pointer +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_presentation_from_w3c( + cred: ObjectHandle, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} +``` + +#### Optional: Methods duplication + +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. + +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 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 +- 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 + +> We can do only part of the work: add duplication methods for presentation but leave old methods for credentials + +```rust +/// Create Credential Offer according to the AnonCreds specification +/// It can be either Indy styled or W3C adopted depending on the answer for Q1 +/// 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 +/// key_proof: object handle pointing to credential definition key correctness proof +/// cred_offer_p - Reference that will contain created credential offer (in Indy form) instance pointer. +/// +/// # Returns +/// 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, +) -> ErrorCode {} + +/// Create Credential Request according to the AnonCreds specification +/// It can be either Indy styled or W3C adopted depending on the answer for Q1 +/// 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 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 +/// cred_def: object handle pointing to credential definition +/// link_secret: holder link secret +/// link_secret_id: id of holder's link secret +/// credential_offer: object handle pointing to credential offer +/// cred_req_p: Reference that will contain created credential request (in Indy form) instance pointer. +/// cred_req_meta_p: Reference that will contain created credential request metadata (in Indy form) instance pointer. +/// +/// # Returns +/// 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, +) -> ErrorCode {} + +/// Create W3C styled Credential according to the specification. +/// +/// # Params +/// cred_def: object handle pointing to the credential definition +/// cred_def_private: object handle pointing to the private part of credential definition +/// cred_offer: object handle pointing to the credential offer +/// cred_request: object handle pointing to the credential request +/// attr_names: list of attribute names +/// attr_raw_values: list of attribute values +/// revocation: object handle pointing to the credential revocation data +/// cred_p: reference that will contain credential (in W3C form) instance pointer +/// +/// # Returns +/// 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, +) -> ErrorCode {} + +/// Process an incoming W3C credential received from the issuer. +/// +/// # Params +/// cred_def: object handle pointing to the credential definition +/// cred_def_private: object handle pointing to the private part of credential definition +/// cred_offer: object handle pointing to the credential offer +/// cred_request: object handle pointing to the credential request +/// attr_names: list of attribute names +/// attr_raw_values: list of attribute values +/// revocation: object handle pointing to the credential revocation data +/// cred_p: reference that will contain credential (in W3C form) instance pointer +/// +/// # Returns +/// 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, +) -> ErrorCode {} + +/// Get value of request credential attribute as string +/// +/// # Params +/// cred_def: object handle pointing to the credential (in W3 form) +/// name: name of attribute to retrieve +/// result_p: reference that will contain value of request credential attribute +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_get_attribute( + handle: ObjectHandle, + name: FfiStr, + result_p: *mut *const c_char, +) -> ErrorCode {} + +/// Create W3C styled Presentation according to the specification. +/// +/// # Params +/// pres_req: object handle pointing to presentation request +/// credentials: credentials (in W3C form) to use for presentation preparation +/// credentials_prove: credentials to use for presentation preparation +/// self_attest_names: list of names of self-attested requested attributes +/// self_attest_values: list of values for self-attested requested attributes +/// link_secret: holder link secret +/// schemas: list of credential schemas +/// schema_ids: list of schemas ids +/// cred_defs: list of credential definitions +/// cred_def_ids: list of credential definitions ids +/// presentation_p: reference that will contain created presentation (in W3C form) instance pointer. +/// +/// # Returns +/// 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, +) -> ErrorCode {} + +/// Create W3C styled Presentation according to the specification. +/// +/// # Params +/// presentation: object handle pointing to presentation +/// pres_req: object handle pointing to presentation request +/// schemas: list of credential schemas +/// schema_ids: list of schemas ids +/// cred_defs: list of credential definitions +/// cred_def_ids: list of credential definitions ids +/// rev_reg_defs: list of revocation definitions +/// rev_reg_def_ids: list of revocation definitions ids +/// rev_status_list: revocation status list +/// nonrevoked_interval_override: not-revoked interval +/// result_p: reference that will contain presentation verification result. +/// +/// # Returns +/// 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, +) -> ErrorCode {} +``` + +#### Optional: Credential Offer / Credential Request Conversion methods + +Methods similar to Credential / Presentation conversion into W3C format. + +> Do not see a sense From 6b3d7e2a23b7bfa125b7dbb99e2fdc5b674eeed3 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Fri, 3 Nov 2023 17:17:01 +0300 Subject: [PATCH 02/13] feat: Work on credential conversion methods Signed-off-by: artem.ivanov --- docs/design/w3c/spec.md | 35 ++- docs/design/w3c/w3c-representation.md | 298 ++++++++++++++++---------- 2 files changed, 209 insertions(+), 124 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..ca0c8319 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,19 +341,16 @@ 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. /// /// # Params -/// pres_req: object handle pointing to presentation request /// credentials: credentials (in W3C form) to use for presentation preparation -/// credentials_prove: credentials to use for presentation preparation -/// self_attest_names: list of names of self-attested requested attributes -/// self_attest_values: list of values for self-attested requested attributes +/// credentials_prove: attributes and predicates to prove per credential /// link_secret: holder link secret /// schemas: list of credential schemas /// schema_ids: list of schemas ids @@ -334,24 +362,20 @@ 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, + 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. /// /// # Params /// presentation: object handle pointing to presentation -/// pres_req: object handle pointing to presentation request /// schemas: list of credential schemas /// schema_ids: list of schemas ids /// cred_defs: list of credential definitions @@ -366,17 +390,16 @@ 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, + 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 +408,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 From 9e7763cd66c9a819ad7852f88b31912d853d81a1 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Mon, 6 Nov 2023 14:37:50 +0300 Subject: [PATCH 03/13] feat: Moved all questions to teh design document and added encoding sample Signed-off-by: artem.ivanov --- docs/design/w3c/encoding.md | 26 +++++++++ docs/design/w3c/spec.md | 50 ------------------ docs/design/w3c/w3c-representation.md | 76 ++++++++++++++++++++++++--- 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/docs/design/w3c/encoding.md b/docs/design/w3c/encoding.md index 5367fba3..6fc86af4 100644 --- a/docs/design/w3c/encoding.md +++ b/docs/design/w3c/encoding.md @@ -7,6 +7,32 @@ Also, due to the fact that fields order matters during serialization/deserializa > TO DISCUSS: For simplicity we still can use straight object JSON serialization and representing as bytes but the size of encoded string will be almost 3 times bigger. +#### Example + +**Signature data:** +``` +{ + "m_2": "57832835556928742723946725004638238236382427793876617639158517726445069815397", + "a": "20335594316731334597758816443885619716281946894071547670112874227353349613733788033617671091848119624077343554670947282810485774124636153228333825818186760397527729892806528284243491342499262911619541896964620427749043381625203893661466943880747122017539322865930800203806065857795584699623987557173946111100450130555197585324032975907705976283592876161733661021481170756352943172201881541765527633833412431874555779986196454199886878078859992928382512010526711165717317294021035408585595567390933051546616905350933492259317172537982279278238456869493798937355032304448696707549688520575565393297998400926856935054785", + "e": "259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742930114221280625468933785621106476195767", + "v": "6264315754962089362691677910875768714719628097173834826942639456162861264780209679632476338104728648674666095282910717315628966174111516324733617604883927936031834134944562245348356595475949760140820205017843765225176947252534891385340037654527825604373031641665762232119470199172203915071879260274922482308419475927587898260844045340005759709509719230224917577081434498505999519246994431019808643717455525020238858900077950802493426663298211783820016830018445034267920428147219321200498121844471986156393710041532347890155773933440967485292509669092990420513062430659637641764166558511575862600071368439136343180394499313466692464923385392375334511727761876368691568580574716011747008456027092663180661749027223129454567715456876258225945998241007751462618767907499044716919115655029979467845162863204339002632523083819", + "se": "16380378819766384687299800964395104347426132415600670073499502988403571039552426989440730562439872799389359320216622430122149635890650280073919616970308875713611769602805907315796100888051513191790990723115153015179238215201014858697020476301190889292739142646098613335687696678474499610035829049097552703970387216872374849734708764603376911608392816067509505173513379900549958002287975424637744258982508227210821445545063280589183914569333870632968595659796744088289167771635644102920825749994200219186110532662348311959247565066406030309945998501282244986323336410628720691577720308242032279888024250179409222261839", + "c": "54687071895183924055442269144489786903186459631877792294627879136747836413523" +} +``` + +**Using [Aries base64 attachment encoding](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url):** +``` +// Length: 3260 +JtXzIiOiAiNTc4MzI4MzU1NTY5Mjg3NDI3MjM5NDY3MjUwMDQ2MzgyMzgyMzYzODI0Mjc3OTM4NzY2MTc2MzkxNTg1MTc3MjY0NDUwNjk4MTUzOTciLCAiYSI6ICIyMDMzNTU5NDMxNjczMTMzNDU5Nzc1ODgxNjQ0Mzg4NTYxOTcxNjI4MTk0Njg5NDA3MTU0NzY3MDExMjg3NDIyNzM1MzM0OTYxMzczMzc4ODAzMzYxNzY3MTA5MTg0ODExOTYyNDA3NzM0MzU1NDY3MDk0NzI4MjgxMDQ4NTc3NDEyNDYzNjE1MzIyODMzMzgyNTgxODE4Njc2MDM5NzUyNzcyOTg5MjgwNjUyODI4NDI0MzQ5MTM0MjQ5OTI2MjkxMTYxOTU0MTg5Njk2NDYyMDQyNzc0OTA0MzM4MTYyNTIwMzg5MzY2MTQ2Njk0Mzg4MDc0NzEyMjAxNzUzOTMyMjg2NTkzMDgwMDIwMzgwNjA2NTg1Nzc5NTU4NDY5OTYyMzk4NzU1NzE3Mzk0NjExMTEwMDQ1MDEzMDU1NTE5NzU4NTMyNDAzMjk3NTkwNzcwNTk3NjI4MzU5Mjg3NjE2MTczMzY2MTAyMTQ4MTE3MDc1NjM1Mjk0MzE3MjIwMTg4MTU0MTc2NTUyNzYzMzgzMzQxMjQzMTg3NDU1NTc3OTk4NjE5NjQ1NDE5OTg4Njg3ODA3ODg1OTk5MjkyODM4MjUxMjAxMDUyNjcxMTE2NTcxNzMxNzI5NDAyMTAzNTQwODU4NTU5NTU2NzM5MDkzMzA1MTU0NjYxNjkwNTM1MDkzMzQ5MjI1OTMxNzE3MjUzNzk4MjI3OTI3ODIzODQ1Njg2OTQ5Mzc5ODkzNzM1NTAzMjMwNDQ0ODY5NjcwNzU0OTY4ODUyMDU3NTU2NTM5MzI5Nzk5ODQwMDkyNjg1NjkzNTA1NDc4NSIsICJlIjogIjI1OTM0NDcyMzA1NTA2MjA1OTkwNzAyNTQ5MTQ4MDY5NzU3MTkzODI3Nzg4OTUxNTE1MjMwNjI0OTcyODU4MzEwNTY2NTgwMDcxMzMwNjc1OTE0OTk4MTY5MDU1OTE5Mzk4NzE0MzAxMjM2NzkxMzIwNjI5OTMyMzg5OTY5Njk0MjIxMzIzNTk1Njc0MjkzMDExNDIyMTI4MDYyNTQ2ODkzMzc4NTYyMTEwNjQ3NjE5NTc2NyIsICJ2IjogIjYyNjQzMTU3NTQ5NjIwODkzNjI2OTE2Nzc5MTA4NzU3Njg3MTQ3MTk2MjgwOTcxNzM4MzQ4MjY5NDI2Mzk0NTYxNjI4NjEyNjQ3ODAyMDk2Nzk2MzI0NzYzMzgxMDQ3Mjg2NDg2NzQ2NjYwOTUyODI5MTA3MTczMTU2Mjg5NjYxNzQxMTE1MTYzMjQ3MzM2MTc2MDQ4ODM5Mjc5MzYwMzE4MzQxMzQ5NDQ1NjIyNDUzNDgzNTY1OTU0NzU5NDk3NjAxNDA4MjAyMDUwMTc4NDM3NjUyMjUxNzY5NDcyNTI1MzQ4OTEzODUzNDAwMzc2NTQ1Mjc4MjU2MDQzNzMwMzE2NDE2NjU3NjIyMzIxMTk0NzAxOTkxNzIyMDM5MTUwNzE4NzkyNjAyNzQ5MjI0ODIzMDg0MTk0NzU5Mjc1ODc4OTgyNjA4NDQwNDUzNDAwMDU3NTk3MDk1MDk3MTkyMzAyMjQ5MTc1NzcwODE0MzQ0OTg1MDU5OTk1MTkyNDY5OTQ0MzEwMTk4MDg2NDM3MTc0NTU1MjUwMjAyMzg4NTg5MDAwNzc5NTA4MDI0OTM0MjY2NjMyOTgyMTE3ODM4MjAwMTY4MzAwMTg0NDUwMzQyNjc5MjA0MjgxNDcyMTkzMjEyMDA0OTgxMjE4NDQ0NzE5ODYxNTYzOTM3MTAwNDE1MzIzNDc4OTAxNTU3NzM5MzM0NDA5Njc0ODUyOTI1MDk2NjkwOTI5OTA0MjA1MTMwNjI0MzA2NTk2Mzc2NDE3NjQxNjY1NTg1MTE1NzU4NjI2MDAwNzEzNjg0MzkxMzYzNDMxODAzOTQ0OTkzMTM0NjY2OTI0NjQ5MjMzODUzOTIzNzUzMzQ1MTE3Mjc3NjE4NzYzNjg2OTE1Njg1ODA1NzQ3MTYwMTE3NDcwMDg0NTYwMjcwOTI2NjMxODA2NjE3NDkwMjcyMjMxMjk0NTQ1Njc3MTU0NTY4NzYyNTgyMjU5NDU5OTgyNDEwMDc3NTE0NjI2MTg3Njc5MDc0OTkwNDQ3MTY5MTkxMTU2NTUwMjk5Nzk0Njc4NDUxNjI4NjMyMDQzMzkwMDI2MzI1MjMwODM4MTkiLCAic2UiOiAiMTYzODAzNzg4MTk3NjYzODQ2ODcyOTk4MDA5NjQzOTUxMDQzNDc0MjYxMzI0MTU2MDA2NzAwNzM0OTk1MDI5ODg0MDM1NzEwMzk1NTI0MjY5ODk0NDA3MzA1NjI0Mzk4NzI3OTkzODkzNTkzMjAyMTY2MjI0MzAxMjIxNDk2MzU4OTA2NTAyODAwNzM5MTk2MTY5NzAzMDg4NzU3MTM2MTE3Njk2MDI4MDU5MDczMTU3OTYxMDA4ODgwNTE1MTMxOTE3OTA5OTA3MjMxMTUxNTMwMTUxNzkyMzgyMTUyMDEwMTQ4NTg2OTcwMjA0NzYzMDExOTA4ODkyOTI3MzkxNDI2NDYwOTg2MTMzMzU2ODc2OTY2Nzg0NzQ0OTk2MTAwMzU4MjkwNDkwOTc1NTI3MDM5NzAzODcyMTY4NzIzNzQ4NDk3MzQ3MDg3NjQ2MDMzNzY5MTE2MDgzOTI4MTYwNjc1MDk1MDUxNzM1MTMzNzk5MDA1NDk5NTgwMDIyODc5NzU0MjQ2Mzc3NDQyNTg5ODI1MDgyMjcyMTA4MjE0NDU1NDUwNjMyODA1ODkxODM5MTQ1NjkzMzM4NzA2MzI5Njg1OTU2NTk3OTY3NDQwODgyODkxNjc3NzE2MzU2NDQxMDI5MjA4MjU3NDk5OTQyMDAyMTkxODYxMTA1MzI2NjIzNDgzMTE5NTkyNDc1NjUwNjY0MDYwMzAzMDk5NDU5OTg1MDEyODIyNDQ5ODYzMjMzMzY0MTA2Mjg3MjA2OTE1Nzc3MjAzMDgyNDIwMzIyNzk4ODgwMjQyNTAxNzk0MDkyMjIyNjE4MzkiLCAiYyI6ICI1NDY4NzA3MTg5NTE4MzkyNDA1NTQ0MjI2OTE0NDQ4OTc4NjkwMzE4NjQ1OTYzMTg3Nzc5MjI5NDYyNzg3OTEzNjc0NzgzNjQxMzUyMyJ9 +``` + +**Using proposed algorithm:** +``` +// Length: 1347 +AAAgf9w5lZgz95dY38QeT0XWJfaGrY-CSr8uDo82jptOTmUBAQChFsSOFc2fDgVDKCSs2KydOLvZbNLFXyB2qlJGTadW1ZBcZ2WvocXcKufEWrbDbTr58ySW_Om1HUmVy-ojBvh4fwAf6XETclSPE8MfctSE09pwpy4ZYpOabSdY2G6mt4U4j5YdCiuCEBnmiG7JaxgdHqW4cG3kSxX1JXmy2rE8S0uHFxqT3H4d2otX0Om9r9e6btmeA0mv4fqfy9gd9y7cxAE4Xw7nQp5y29yhA93gpHmfV0FNcEzvgmFBGhF5DzMEYGM7Bmoxip3zmlXDpn4Z3Q-SQWKuO1SEa-YPEjc7OkQN8GjEweQAP6zUNoDD7FQtGdhXsJ0gq9tLz_Xw_x3BAgBLEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVC4ox7flXlg7AEkAhB-3AwFVCeRcF6Ii4FMqDfJ04FB_vm7NdqoWcfHARRmFzgUgMYoiB04kz5CDzzIVuowqkIbRgrlC7CKryuzuqNiCF3mfQkvJWfK3qXFNBKp2ZBVxYUo92l0LbE0cBAG3p_ZB26PO5XSS8Nw8U7uWJPkG0rQxreZcgEtw1WFNEzfpiTLN-W4xGneTYqot3VDFMXjmn0i37nPhdSSvfnSkk6PDJWi8H5Op-Zm03f5o6cWTW-vyL0p8x0dcvYGLPxDSLnbeP0Fc95KewHAtfWSn4gdQ7C2fzc8pZ9UV9iUIIDtdhDV306h-ZUhO641o2BTIa3fDQi7X590gIdhYhAUfIarHGzvXdff6OatwALnJqhAY2jbGopyrpgsTb9i7SOYwkztTJbHQ139Syv75uJ1rrGDzm_feXNGvM-ta8sr4sdD51vcOhVlFeDPD3R8iEqNbOGuj6-wJlmyF8CsEAQCBwfG7CL3X9rS6GkDsCmkw18__K8cSaePD4YWFDQHBqnzu6nOIy6RGa8U6tXgJbqZPGcBg9Db6W0iwkub9N36nadgqjPQkhuxt0U8H-p6NkPfbqqjZ3dDqNmDAuvr96_MItOSdPI_kRhyhJK9779Lg6iWyakimJ1QViqsefO-1uE-MQ0FXqs4ZcC-V187LXc2IHpJwk2d8Oo66oQij__Gcn4h0qQf0rC8TNy54_IQTSns080AK7Yfy12nMWBnWJN_7d4CToSpDAehyn2YEBPmweGuVnXu-DEjAbeEGFbsTYsCHygo_yzBpndRguYruDzn2yyt3RkyWISFYRZzEL1xPBQAgeOfJKl30pg6m-np2OmrRYp8Z_x3FqdwRHoWruiF0FlM +``` + ##### Encoding steps 1. Iterate over object `attributes` diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md index 9cd9502e..8ae7012e 100644 --- a/docs/design/w3c/spec.md +++ b/docs/design/w3c/spec.md @@ -131,22 +131,6 @@ In the case of W3C AnonCreds credentials, the `credentialSubject` attribute look } ``` -* **TO DISCUSS**: W3C data model allows attributes to be represented not only as key/value string pairs but also as - objects and arrays. - * If we want to support more complex representations for the W3C AnonCreds credential attributes and their - presentations, we need to design following things: - * how encoding will work for such attributes - * how selective disclosure will work on top level attribute itself - ``` - "credentialSubject": { - "address": { - "type": "Address", - "city": "Foo", - "street": "Main str." - } - } - ``` - #### Data Schemas W3C [Credential Subject](https://www.w3.org/TR/vc-data-model/#data-schemas) section defines an optional capability to @@ -260,11 +244,6 @@ entry: * encoded as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url) - -* **TO DISCUSS**: Signature/Proof encoding: Which approach to use for encoding? - * Basic approach used in Aries attachments: Base 64 encoding of object serialized as JSON string - * Compact encoding implementing in Python PoC: Using the fact that most fields of credential signature and proof are big numbers - ##### Data Integrity proof In order to better conform to the W3C specification AnonCreds based credential also requires including @@ -475,35 +454,6 @@ type pointing to the difference in a presentation structure and looks the follow * `unrevealedAttributes` - list of requested attributes presented in the credential but left unrevealed * `requestedPredicates` - list of predicates resolved using the credential - -* **TO DISCUSS**: Should we remove `mapping` completely or move under encoded `proofValue`? - * Why `mapping` is bad: we make presentation tied to Indy styled Presentation Request - * Mapping is something old indy-fashioned required for validation (not signature verification) that proof matches to - the request itself on the verifier side - * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with - type) - - -* **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 W3C [Proofs (Signatures)](https://www.w3.org/TR/vc-data-model/#proofs-signatures) section requires including of `proof` diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index ca0c8319..80be01f9 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -49,15 +49,61 @@ verifiable credential and presentation described in the [document](). * 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? + * Basic approach used in Aries attachments: [BaseURL safe 64 encoding of object serialized as JSON string](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url)? + * Compact encoding implemented in Python PoC: Using the fact that most fields of credential signature and proof are big numbers rather that strings. + * For example: the length of encoded credential signature string is about 2.5 times less than in the basic approach + * Find an [example data](./encoding.md#example) to see the difference * Proposed answer: Start from basic approach? -* Q6: Should we care about back way conversion of credential issued in W3C form? +* Q6: W3C data model allows attributes to be represented not only as key/value string pairs but also as + objects and arrays. + * If we want to support more complex representations for the W3C AnonCreds credential attributes and their + presentations, we need to design following things: + * how encoding will work for such attributes + * how selective disclosure will work on top level attribute itself + ``` + "credentialSubject": { + "address": { + "type": "Address", + "city": "Foo", + "street": "Main str." + } + } + ``` +* Q7: 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 +* Q8: Should we include Holder DID into credential subject as [`id` attribute](https://www.w3.org/TR/vc-data-model/#identifiers)? + * This enables credential subject [validation](https://www.w3.org/TR/vc-data-model/#credential-subject-0) + * We can add if for newly issued credentials but cannot set during the conversion of previously issued credentials. +* Q9: 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" + } + ... + } + ``` +* Q10: Should we remove `mapping` completely or move under encoded `proofValue`? + * Why `mapping` is bad: we make presentation tied to Indy styled Presentation Request + * Mapping is something old indy-fashioned required for doing validation (not signature verification) that proof matches to + the request itself on the verifier side + * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with + type) + * `revealed attributes` and `predicates` can be validated as we include them into `credentialSubject` but `unrevealed` attributes cannot. + ### Proposed implementation path for first iteration @@ -347,6 +393,8 @@ pub extern "C" fn anoncreds_w3c_credential_get_attribute( ) -> ErrorCode {} /// Create W3C styled Presentation according to the specification. +/// +/// TODO: Function parameters need to be reworked if we decide to make it Presentation Request format agnostic /// /// # Params /// credentials: credentials (in W3C form) to use for presentation preparation @@ -374,6 +422,8 @@ pub extern "C" fn anoncreds_w3c_create_presentation( /// Create W3C styled Presentation according to the specification. /// +/// TODO: Function parameters need to be reworked if we decide to make it Presentation Request format agnostic +/// /// # Params /// presentation: object handle pointing to presentation /// schemas: list of credential schemas @@ -416,28 +466,38 @@ Methods similar to Credential / Presentation conversion into W3C format. #### Issue Indy Credential and present W3C Presentation ``` +/// Issue Indy-styled credential using existing methods 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,...) +/// Convert Indy-styled credential to W3C credential form 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) +/// Do wallets need to store both credential forms to handle Indy and DIF presentations requests? + +/// Verifiy W3C preentation using converted W3C crdential form +w3c_presentation_request = Verifier.w3c_create_presentation_request() +w3c_presentation = Holder.anoncreds_w3c_create_presentation(w3c_presentation_request, w3c_credentials) Verifier.anoncreds_w3c_verify_presentation(w3c_presentation) ``` #### Issue W3C Credential and present Indy Presentation ``` +/// Issue W3C credential using new flow methods 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,...) +/// Convert W3C credential to Indy form indy_credential = Holder.anoncreds_credential_from_w3c(w3c_credential) +/// Do wallets need to store both credential forms to handle Indy and DIF presentations requests? + +/// Verifiy Indy presentation using converted Iny crdential form indy_presentation_request = Verifier.create_presentation_request() indy_presentation = Holder.create_presentation(indy_presentation_request, indy_credential) Verifier.anoncreds_verify_presentation(indy_presentation) @@ -446,12 +506,14 @@ Verifier.anoncreds_verify_presentation(indy_presentation) #### Issue W3C Credential and present W3C Presentation ``` +/// Issue W3C credential using new flow methods 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() +/// Verifiy W3C presenttion using W3C crdential form +w3c_presentation_request = Verifier.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 From 44d93ca25728d8179fa585d2b0ceaea42ca4fd6a Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Mon, 6 Nov 2023 16:19:16 +0300 Subject: [PATCH 04/13] feat: Replaced usages of indy-styled with legacy styled Signed-off-by: artem.ivanov --- docs/design/w3c/spec.md | 18 ++--- docs/design/w3c/w3c-representation.md | 102 +++++++++++++------------- 2 files changed, 58 insertions(+), 62 deletions(-) diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md index 8ae7012e..7c6cf0f5 100644 --- a/docs/design/w3c/spec.md +++ b/docs/design/w3c/spec.md @@ -1,6 +1,6 @@ ## W3C Verifiable Credentials Representation -This section describes how Indy-styled AnonCreds credentials can be represented in the form of W3C Verifiable +This section describes how legacy AnonCreds credentials can be represented in the form of W3C Verifiable Credentials standard. ### Credential @@ -141,7 +141,7 @@ In the context of W3C AnonCreds credentials defined a custom `AnonCredsDefinitio following information to credential: In the case of W3C AnonCreds credentials, the `credentialSchema` attribute defines a custom `AnonCredsDefinition` -schema in order to include the information about Indy related definitions to credential and looks the following: +schema in order to include the information about AnonCreds related definitions to credential and looks the following: ``` { @@ -156,8 +156,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 +* `schema` - id of AnonCreds Schema +* `definition` - id of AnonCreds Credential Definition * `revocation` - Revocation Registry Accumulator value * `witness` - Witness value * `encoding` - attributes encoding algorithm @@ -232,7 +232,7 @@ entry: * `type` - `CLSignature2022` * `signature` - credential signature - * signature received by building the following object from indy styled credential: + * signature received by building the following object: ``` { "signature": {..}, @@ -257,7 +257,7 @@ Including Data Integrity proof allows to use verifiable credential without acces W3C [Expiration](https://www.w3.org/TR/vc-data-model/#expiration) section defines an optional capability to include credential expiration information. -Instead of including `expirationDate` property we recommend using a standard indy credentials revocation approach and +Instead of including `expirationDate` property we recommend using a standard AnonCreds credentials revocation approach and include a revocation registry id into the credential schema. #### Status @@ -265,7 +265,7 @@ include a revocation registry id into the credential schema. W3C [Status](https://www.w3.org/TR/vc-data-model/#status) section defines an optional capability to include credential status information. -Instead of including `credentialStatus` property we recommend using a standard indy credentials revocation approach and +Instead of including `credentialStatus` property we recommend using a standard AnonCreds credentials revocation approach and include a revocation registry id into the credential schema. ### Presentation @@ -439,7 +439,7 @@ type pointing to the difference in a presentation structure and looks the follow **Verifiable Credential Proof structure** * `proofValue` - encoded proof generated for each specific credential - * object created from Indy styled credential sub proof + * proof value received by building the following object: ``` { primaryProof: {..}, @@ -485,7 +485,7 @@ presentation: * `challenge` - nonce taken from the presentation request * `aggregated` - encoded aggregated proof value - * object created from Indy proof data + * proof value received by building the following object: ``` { aggregated: {..}, diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 80be01f9..c7c18b7c 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -1,6 +1,6 @@ ## Design for W3C representation of AnonCreds credentials and presentation -Currently `anoncreds-rs` library only provides support for Indy styled AnonCreds credentials matching to +Currently `anoncreds-rs` library only provides support for legacy 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 @@ -8,13 +8,13 @@ verifiable credential and presentation described in the [document](). ### Goals and ideas -* Use Indy styled credentials to generate W3C AnonCreds credentials and presentations +* Use legacy 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 + * Convert legacy styled AnonCreds credentials into W3C form + * Convert W3C styled AnonCreds credentials into legacy form * Presentation conversion (Optional): - * Convert Indy styled AnonCreds presentation into W3C form - * Convert W3C styled AnonCreds presentation into Indy form + * Convert legacy styled AnonCreds presentation into W3C form + * Convert W3C styled AnonCreds presentation into legacy form * Extend W3C credentials: * Ability to set Data Integrity proof signatures for generated W3C credential objects: * W3C credentials may contain multiple signatures @@ -38,7 +38,7 @@ verifiable credential and presentation described in the [document](). * 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? +* Q3: Are we still tied to legacy 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. @@ -70,7 +70,7 @@ verifiable credential and presentation described in the [document](). } ``` * Q7: 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 + * Assume that we issued W3C which cannot convert back into legacy 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 @@ -97,8 +97,8 @@ verifiable credential and presentation described in the [document](). } ``` * Q10: Should we remove `mapping` completely or move under encoded `proofValue`? - * Why `mapping` is bad: we make presentation tied to Indy styled Presentation Request - * Mapping is something old indy-fashioned required for doing validation (not signature verification) that proof matches to + * Why `mapping` is bad: we make presentation tied to legacy styled Presentation Request + * Mapping is something old-fashioned synthetic required for doing validation (not signature verification) that proof matches to the request itself on the verifier side * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with type) @@ -129,16 +129,16 @@ is require application uses conversion methods to get required format. 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 +Methods purpose - have to forms of credentials (probably even duplicate in wallet) to cover both cases: legacy and W3C +* `anoncreds_credential_to_w3c` - create W3C Presentation using a credential previously issued in legacy form +* `anoncreds_credential_from_w3c` - create a legacy styled presentation (for legacy Verifier) using a credential issued in W3C form ```rust -/// Convert Indy styled AnonCreds credential into W3C AnonCreds credential form +/// Convert legacy styled AnonCreds credential into W3C AnonCreds credential form /// The conversion process described at the specification: --- /// /// # Params -/// cred - object handle pointing to Indy styled credential to convert +/// cred - object handle pointing to legacy styled credential to convert /// cred_p - reference that will contain converted credential (in W3C form) instance pointer /// /// # Returns @@ -149,12 +149,12 @@ pub extern "C" fn anoncreds_credential_to_w3c( cred_p: *mut ObjectHandle, ) -> ErrorCode {} -/// Convert W3C styled AnonCreds credential into Indy styled credential +/// Convert W3C styled AnonCreds credential into legacy 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 +/// cred_p - reference that will contain converted credential (in legacy form) instance pointer /// /// # Returns /// Error code @@ -201,15 +201,15 @@ pub extern "C" fn anoncreds_w3c_credential_set_integrity_proof( 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 +In this case, library will provide APIs to create/verify legacy 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 +/// Convert legacy styled AnonCreds presentation into W3C AnonCreds presentation form /// The conversion process described at the specification: --- /// /// # Params -/// cred - object handle pointing to Indy styled AnonCreds presentation to convert +/// cred - object handle pointing to legacy styled AnonCreds presentation to convert /// cred_p - reference that will contain converted presentation (in W3C form) instance pointer /// /// # Returns @@ -220,12 +220,12 @@ pub extern "C" fn anoncreds_presentation_to_w3c( cred_p: *mut ObjectHandle, ) -> ErrorCode {} -/// Convert W3C styled AnonCreds presentation into Indy styled AnonCreds credential +/// Convert W3C styled AnonCreds presentation into legacy styled AnonCreds presentation /// The conversion process described at the specification: --- /// /// # Params /// cred - object handle pointing to W3C styled AnonCreds presentation to convert -/// cred_p - reference that will contain converted presentation (in Indy form) instance pointer +/// cred_p - reference that will contain converted presentation (in legacy form) instance pointer /// /// # Returns /// Error code @@ -259,11 +259,11 @@ The reasons for adding duplication methods: - 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 + - issuer creates offer in legacy form but with resulting credential format indication (legacy or w3c ) + - as the flow execution result, create credential function returns credential either in w3c or legacy form depending on offer - if application analyze credential somehow it cause difficulties -- easier deprecation of indy styled credentials and APIs +- easier deprecation of legacy 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 @@ -271,10 +271,8 @@ The reasons for adding duplication methods: ```rust /// Create Credential Offer according to the AnonCreds specification -/// It can be either Indy styled or W3C adopted depending on the answer for Q1 -/// 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? +/// It can be either legacy styled or W3C adopted depending on the answer for Q1 +/// If legacy styled credential to be used, it should indicate that credential in W3C AnonCreds form will be issued as the result. /// /// Even if we do not change Credential Offer message itself we start from using a separate set of API functions /// @@ -282,7 +280,7 @@ The reasons for adding duplication methods: /// schema_id: id of schema future credential refers to /// cred_def_id: id of credential definition future credential refers to /// key_proof: object handle pointing to credential definition key correctness proof -/// cred_offer_p - Reference that will contain created credential offer (in Indy form) instance pointer. +/// cred_offer_p - Reference that will contain created credential offer (in legacy form) instance pointer. /// /// # Returns /// Error code @@ -295,10 +293,8 @@ pub extern "C" fn anoncreds_w3c_create_credential_offer( ) -> ErrorCode {} /// Create Credential Request according to the AnonCreds specification -/// It can be either Indy styled or W3C adopted depending on the answer for Q1 -/// 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 Request for W3C form? +/// It can be either legacy styled or W3C adopted depending on the answer for Q1 +/// If legacy styled credential to be used, it should indicate that credential in W3C AnonCreds form will be issued as the result. /// /// Even if we do not change Credential Request message itself we start from using a separate set of API functions /// @@ -309,8 +305,8 @@ pub extern "C" fn anoncreds_w3c_create_credential_offer( /// link_secret: holder link secret /// link_secret_id: id of holder's link secret /// credential_offer: object handle pointing to credential offer -/// cred_req_p: Reference that will contain created credential request (in Indy form) instance pointer. -/// cred_req_meta_p: Reference that will contain created credential request metadata (in Indy form) instance pointer. +/// cred_req_p: Reference that will contain created credential request (in legacy form) instance pointer. +/// cred_req_meta_p: Reference that will contain created credential request metadata (in legacy form) instance pointer. /// /// # Returns /// Error code @@ -463,19 +459,19 @@ Methods similar to Credential / Presentation conversion into W3C format. > IN PROGRESS -#### Issue Indy Credential and present W3C Presentation +#### Issue legacy Credential and present W3C Presentation ``` -/// Issue Indy-styled credential using existing methods -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,...) +/// Issue legacy styled credential using existing methods +legacy_credential_offer = Issuer.anoncreds_create_credential_offer(...) +legacy_credential_request = Holder.anoncreds_create_credential_request(legacy_credential_offer,...) +legacy_credential = Issuer.anoncreds_create_credential(legacy_credential_request,...) +legacy_credential = Holder.anoncreds_process_credential(legacy_credential,...) -/// Convert Indy-styled credential to W3C credential form -w3c_credential = Holder.anoncreds_credential_to_w3c(indy_credential) +/// Convert legacy styled credential to W3C credential form +w3c_credential = Holder.anoncreds_credential_to_w3c(legacy_credential) -/// Do wallets need to store both credential forms to handle Indy and DIF presentations requests? +/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? /// Verifiy W3C preentation using converted W3C crdential form w3c_presentation_request = Verifier.w3c_create_presentation_request() @@ -483,7 +479,7 @@ w3c_presentation = Holder.anoncreds_w3c_create_presentation(w3c_presentation_req Verifier.anoncreds_w3c_verify_presentation(w3c_presentation) ``` -#### Issue W3C Credential and present Indy Presentation +#### Issue W3C Credential and present legacy Presentation ``` /// Issue W3C credential using new flow methods @@ -492,15 +488,15 @@ w3c_credential_request = Holder.anoncreds_w3c_create_credential_request(w3c_cred w3c_credential = Issuer.anoncreds_w3c_create_credential(w3c_credential_request,...) w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...) -/// Convert W3C credential to Indy form -indy_credential = Holder.anoncreds_credential_from_w3c(w3c_credential) +/// Convert W3C credential to legacy form +legacy_credential = Holder.anoncreds_credential_from_w3c(w3c_credential) -/// Do wallets need to store both credential forms to handle Indy and DIF presentations requests? +/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? -/// Verifiy Indy presentation using converted Iny crdential form -indy_presentation_request = Verifier.create_presentation_request() -indy_presentation = Holder.create_presentation(indy_presentation_request, indy_credential) -Verifier.anoncreds_verify_presentation(indy_presentation) +/// Verifiy legacy presentation using converted Iny crdential form +legacy_presentation_request = Verifier.create_presentation_request() +legacy_presentation = Holder.create_presentation(legacy_presentation_request, legacy_credential) +Verifier.anoncreds_verify_presentation(legacy_presentation) ``` #### Issue W3C Credential and present W3C Presentation From 4a273bcefc26de67a77ca4b4e8200d8a44dd1d5b Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Tue, 7 Nov 2023 08:44:30 +0300 Subject: [PATCH 05/13] feat: Process review comments Signed-off-by: artem.ivanov --- docs/design/w3c/spec.md | 10 ++- docs/design/w3c/w3c-representation.md | 89 +++++++++++++++------------ 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md index 7c6cf0f5..c39949ee 100644 --- a/docs/design/w3c/spec.md +++ b/docs/design/w3c/spec.md @@ -244,14 +244,12 @@ entry: * encoded as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url) -##### Data Integrity proof +##### non-AnonCreds Integrity proof -In order to better conform to the W3C specification AnonCreds based credential also requires including -of [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs) which must be generated using one +In order to better conform to the W3C specification AnonCreds based credential also allow including +of non-AnonCreds [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs) which must be generated using one of NIST-approved algorithms (RSA, ECDSA, EdDSA). -Including Data Integrity proof allows to use verifiable credential without access to a Ledger. - #### Expiration W3C [Expiration](https://www.w3.org/TR/vc-data-model/#expiration) section defines an optional capability to include @@ -467,7 +465,7 @@ It is verifier and holder responsibility to negotiate which proof must be used ( presentation: * Generate an W3C AnonCreds presentation, with all it’s privacy-preserving power and predicates -* Present the VC using one of Integrity Proof Signatures +* Present the VC using one of non-AnonCreds Integrity Proof Signatures ``` { diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index c7c18b7c..74c6b811 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -12,7 +12,7 @@ verifiable credential and presentation described in the [document](). * Credentials conversion: * Convert legacy styled AnonCreds credentials into W3C form * Convert W3C styled AnonCreds credentials into legacy form - * Presentation conversion (Optional): + * Presentation conversion (Optional): * Convert legacy styled AnonCreds presentation into W3C form * Convert W3C styled AnonCreds presentation into legacy form * Extend W3C credentials: @@ -22,9 +22,9 @@ verifiable credential and presentation described in the [document](). #### 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 +* Credentials: Verify validity of non-AnonCreds Data Integrity proof signatures +* Presentations: Create presentation using non-AnonCreds Data Integrity proof signature +* Presentations: Verify validity of presentations including non-AnonCreds Data Integrity proof signatures * Presentations: Support different formats (for example DIF) of Presentation Request ### Question impacting the approach @@ -32,28 +32,28 @@ verifiable credential and presentation described in the [document](). * 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? - * Proposed answer: no conversion for the current phase + * Answer: No conversion for Credential Offer, Credential Request objects * 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 + * Answer: All methods will be duplicated * Q3: Are we still tied to legacy 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? + * Answer: Keep API tied to existing AnonCreds Presentation Request format +* Q4: Do we want to provide general interfaces doing signing and verification of Non-AnonCreds 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` + * Answer: No. Third party libraries must be used for doing signing and verification of Non-AnonCreds Data Integrity proof signature * Q5: Signature/Proof encoding: Which approach to use for encoding? * Basic approach used in Aries attachments: [BaseURL safe 64 encoding of object serialized as JSON string](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url)? * Compact encoding implemented in Python PoC: Using the fact that most fields of credential signature and proof are big numbers rather that strings. * For example: the length of encoded credential signature string is about 2.5 times less than in the basic approach * Find an [example data](./encoding.md#example) to see the difference - * Proposed answer: Start from basic approach? + * Answer: Start from basic Aries encoding. Experiment with other algorithms as a next step. * Q6: W3C data model allows attributes to be represented not only as key/value string pairs but also as objects and arrays. * If we want to support more complex representations for the W3C AnonCreds credential attributes and their @@ -69,14 +69,17 @@ verifiable credential and presentation described in the [document](). } } ``` + * Answer: For current implementation we only support key/value string pairs * Q7: Should we care about back way conversion of credential issued in W3C form? * Assume that we issued W3C which cannot convert back into legacy 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 + * Answer: Yes. Within the current design/effort credentials must be convertible back and forth * Q8: Should we include Holder DID into credential subject as [`id` attribute](https://www.w3.org/TR/vc-data-model/#identifiers)? * This enables credential subject [validation](https://www.w3.org/TR/vc-data-model/#credential-subject-0) * We can add if for newly issued credentials but cannot set during the conversion of previously issued credentials. + * Answer: Up to Issuer, Optionally Issuer may include DID into credential subject * Q9: 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) @@ -96,6 +99,7 @@ verifiable credential and presentation described in the [document](). ... } ``` + * Answer: Need more discussion * Q10: Should we remove `mapping` completely or move under encoded `proofValue`? * Why `mapping` is bad: we make presentation tied to legacy styled Presentation Request * Mapping is something old-fashioned synthetic required for doing validation (not signature verification) that proof matches to @@ -108,14 +112,12 @@ verifiable credential and presentation described in the [document](). ### Proposed implementation path for first iteration 1. Credential conversion APIs -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` +2. Credential helper methods for non-AnonCreds integrity proof handling (set_integrity_proof, etc?) + * Generation and verification of non-AnonCreds 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 - 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 +3. Flow duplication APIs: All methods +4. No adoption of Credential Offer and Credential Request objects for W3C standard +5. Keep API stick to existing Presentation Request format ### Public API @@ -165,27 +167,13 @@ pub extern "C" fn anoncreds_credential_from_w3c( ) -> ErrorCode {} ``` -#### Credential object methods +#### Credential object helper methods ```rust -/// Get W3C credential payload to sign for making Identity Proof -/// -/// # Params -/// cred - object handle pointing to W3C styled AnonCreds credential -/// signing_payload_p - reference that will contain payload to sign for generation of data integrity proof -/// -/// # Returns -/// Error code -#[no_mangle] -pub extern "C" fn anoncreds_w3c_credential_get_signing_payload( - cred: ObjectHandle, - signing_payload_p: *mut *const c_char, -) -> ErrorCode {} - /// Set Data Integrity proof signature for W3C AnonCreds credential /// /// # Params -/// cred - object handle pointing to W3C styled AnonCreds credential +/// cred - object handle pointing to W3C AnonCreds credential /// proof - data integrity proof signature as JSON string /// /// # Returns @@ -449,12 +437,6 @@ pub extern "C" fn anoncreds_w3c_verify_presentation( ) -> ErrorCode {} ``` -#### Optional: Credential Offer / Credential Request Conversion methods - -Methods similar to Credential / Presentation conversion into W3C format. - -> Do not see a sense - ### Demo scripts > IN PROGRESS @@ -472,6 +454,8 @@ legacy_credential = Holder.anoncreds_process_credential(legacy_credential,...) w3c_credential = Holder.anoncreds_credential_to_w3c(legacy_credential) /// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? +Wallet.store_legacy_credential(legacy_credential) +Wallet.store_w3c_credential(w3c_credential) /// Verifiy W3C preentation using converted W3C crdential form w3c_presentation_request = Verifier.w3c_create_presentation_request() @@ -492,6 +476,8 @@ w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...) legacy_credential = Holder.anoncreds_credential_from_w3c(w3c_credential) /// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? +Wallet.store_legacy_credential(legacy_credential) +Wallet.store_w3c_credential(w3c_credential) /// Verifiy legacy presentation using converted Iny crdential form legacy_presentation_request = Verifier.create_presentation_request() @@ -508,8 +494,33 @@ w3c_credential_request = Holder.anoncreds_w3c_create_credential_request(w3c_cred w3c_credential = Issuer.anoncreds_w3c_create_credential(w3c_credential_request,...) w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...) +/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? +Wallet.store_w3c_credential(w3c_credential) + /// Verifiy W3C presenttion using W3C crdential form w3c_presentation_request = Verifier.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, set RSA Identity Proof signature, and present W3C Presentation using RSA Identity Proof + +``` +/// Issue W3C credential using new flow methods +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,...) + +/// Add RSA Identity Proof signature to credential +integrity_proof = extartnal_library.create_rsa_integrity_proof(w3c_credential) +w3c_credential.set_integrity_proof(integrity_proof) + +/// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? +Wallet.store_w3c_credential(w3c_credential) + +/// Verifiy W3C presenttion using RSA Identity Proof signature +w3c_presentation_request = Verifier.w3c_create_presentation_request() +rsa_integrity_proof_presentation = extartnal_library.create_presentation_using_rsa_integrity_proof(w3c_presentation_request, w3c_credential) +extartnal_verifier.verify_rsa_integrity_proof_presentation(rsa_integrity_proof_presentation) ``` \ No newline at end of file From 580bd342f6935cfcd54dc758aeccf24678e0717c Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Thu, 9 Nov 2023 13:11:40 +0300 Subject: [PATCH 06/13] feat: Documentation update Signed-off-by: artem.ivanov --- docs/design/w3c/context.json | 25 ++-- docs/design/w3c/spec.md | 132 +++++++++--------- docs/design/w3c/w3c-representation.md | 185 ++++++++++++++++---------- 3 files changed, 192 insertions(+), 150 deletions(-) diff --git a/docs/design/w3c/context.json b/docs/design/w3c/context.json index ce254499..9e31c2f2 100644 --- a/docs/design/w3c/context.json +++ b/docs/design/w3c/context.json @@ -20,8 +20,8 @@ "@id": "ac:schema", "@type": "@id" }, - "revocation": { - "@id": "ac:revocation", + "revocation_registry": { + "@id": "ac:revocation_registry", "@type": "@id" }, "encoding": { @@ -43,20 +43,13 @@ "@context": { "@version": 1.1, "@protected": true, - "credential": { - "@id": "ac:credentialProof", - "@context": { - "@version": 1.1, - "@protected": true, - "mapping": { - "@id": "ac:attributeMapping", - "@type": "@json" - }, - "proofValue": { - "@id": "ac:proofValue", - "@type": "xsd:string" - } - } + "mapping": { + "@id": "ac:attributeMapping", + "@type": "@json" + }, + "timestamp": { + "@id": "ac:timestamp", + "@type": "xsd:decimal" }, "proofValue": { "@id": "ac:proofValue", diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md index c39949ee..12ac0224 100644 --- a/docs/design/w3c/spec.md +++ b/docs/design/w3c/spec.md @@ -14,7 +14,7 @@ Example of an AnonCreds W3C formatted credential which will be explained in deta { "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://github.io/anoncreds-w3c/context.json" + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" ], "type": [ "VerifiableCredential", @@ -158,8 +158,7 @@ schema in order to include the information about AnonCreds related definitions t * `schema` - id of AnonCreds Schema * `definition` - id of AnonCreds Credential Definition -* `revocation` - Revocation Registry Accumulator value -* `witness` - Witness value +* `revocation_registry` - (Optional) id of AnonCreds Revocation Registry * `encoding` - attributes encoding algorithm * encoded credential attribute values (binary representation required for doing CL signatures) are not included neither to `credentialSubject` or `signature` @@ -244,10 +243,14 @@ entry: * encoded as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url) +> Note that `rev_reg` and `witness` are only should be set in Issuer's signature. +> After processing the credential signature on the Holder's side these data can be cleaned to reduce the credential size + ##### non-AnonCreds Integrity proof In order to better conform to the W3C specification AnonCreds based credential also allow including -of non-AnonCreds [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs) which must be generated using one +of non-AnonCreds [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs) which must be +generated using one of NIST-approved algorithms (RSA, ECDSA, EdDSA). #### Expiration @@ -255,7 +258,8 @@ of NIST-approved algorithms (RSA, ECDSA, EdDSA). W3C [Expiration](https://www.w3.org/TR/vc-data-model/#expiration) section defines an optional capability to include credential expiration information. -Instead of including `expirationDate` property we recommend using a standard AnonCreds credentials revocation approach and +Instead of including `expirationDate` property we recommend using a standard AnonCreds credentials revocation approach +and include a revocation registry id into the credential schema. #### Status @@ -263,7 +267,8 @@ include a revocation registry id into the credential schema. W3C [Status](https://www.w3.org/TR/vc-data-model/#status) section defines an optional capability to include credential status information. -Instead of including `credentialStatus` property we recommend using a standard AnonCreds credentials revocation approach and +Instead of including `credentialStatus` property we recommend using a standard AnonCreds credentials revocation approach +and include a revocation registry id into the credential schema. ### Presentation @@ -278,7 +283,7 @@ Example of an AnonCreds W3C presentation which will be explained in details: { "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://github.io/anoncreds-w3c/context.json" + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" ], "type": [ "VerifiablePresentation", @@ -288,7 +293,7 @@ Example of an AnonCreds W3C presentation which will be explained in details: { "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://github.io/anoncreds-w3c/context.json" + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" ], "type": [ "VerifiableCredential", @@ -306,37 +311,35 @@ Example of an AnonCreds W3C presentation which will be explained in details: "firstName": "Alice" }, "proof": { - "type": "AnonCredsPresentationProof2022", - "credential": { - "mapping": { - "revealedAttributes": [ - { - "name": "firstName", - "referent": "attribute_0" - } - ], - "unrevealedAttributes": [ - { - "name": "lastName", - "referent": "attribute_1" - } - ], - "requestedPredicates": [ - { - "name": "age", - "p_type": "<", - "value": 18, - "referent": "predicate_1" - } - ] - }, - "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" - } + "type": "AnonCredsPresentationProof2023", + "mapping": { + "revealedAttributes": [ + { + "name": "firstName", + "referent": "attribute_0" + } + ], + "unrevealedAttributes": [ + { + "name": "lastName", + "referent": "attribute_1" + } + ], + "requestedPredicates": [ + { + "name": "age", + "p_type": "<", + "value": 18, + "referent": "predicate_1" + } + ] + }, + "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" } } ], "proof": { - "type": "AnonCredsPresentationProof2022", + "type": "AnonCredsPresentationProof2023", "challenge": "182453895158932070575246", "proofValue": "AAAgtMR4....J19l-agSA" } @@ -400,37 +403,36 @@ The values of verifiable credentials are mostly constructed the same as describe the [Credential Structure](#credential) section. The only difference is the value of the `proof` property. -In the case of W3C AnonCreds presentations, the `proof` attribute uses defined `AnonCredsPresentationProof2022` +In the case of W3C AnonCreds presentations, the `proof` attribute uses defined `AnonCredsPresentationProof2023` type pointing to the difference in a presentation structure and looks the following: ``` "proof": { - "type": "AnonCredsPresentationProof2022", - "credential": { - "mapping": { - "revealedAttributes": [ - { - "name": "firstName", - "referent": "attribute_0" - } - ], - "unrevealedAttributes": [ - { - "name": "lastName", - "referent": "attribute_1" - } - ], - "requestedPredicates": [ - { - "name": "age", - "p_type": "<", - "value": 18, - "referent": "predicate_1" - } - ] + "type": "AnonCredsPresentationProof2023", + "mapping": { + "revealedAttributes": [ + { + "name": "firstName", + "referent": "attribute_0" + } + ], + "unrevealedAttributes": [ + { + "name": "lastName", + "referent": "attribute_1" + } + ], + "requestedPredicates": [ + { + "name": "age", + "p_type": "<", + "value": 18, + "referent": "predicate_1" + } + ] }, - "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" - } + "timestamp": Option<1234567>, + "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw"**** } ``` @@ -440,8 +442,7 @@ type pointing to the difference in a presentation structure and looks the follow * proof value received by building the following object: ``` { - primaryProof: {..}, - nonRevocProof: {..} + sub_proof: {..} } ``` * encoded @@ -451,6 +452,8 @@ type pointing to the difference in a presentation structure and looks the follow * `revealedAttributes` - list of requested attributes revealed using the credential * `unrevealedAttributes` - list of requested attributes presented in the credential but left unrevealed * `requestedPredicates` - list of predicates resolved using the credential +* `timestamp` - (Optional) if revocation supported and requested, time as a total number of seconds from Unix Epoch + representing pointing to the specif moment of revocation registry #### Proof @@ -471,7 +474,7 @@ presentation: { ... "proof": { - "type": "AnonCredsPresentationProof2022", + "type": "AnonCredsPresentationProof2023", "challenge": "182453895158932070575246", "proofValue": "AAAgtMR4DrkY--ZVgKHmUANE04ET7TzUxZ0vZmVcNt4nCkwBABUACQJ69kJVIxHVAQAIAaJ19l-agSA" } @@ -491,3 +494,4 @@ presentation: ``` * encoded as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url). + diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 74c6b811..9cac6078 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -12,18 +12,22 @@ verifiable credential and presentation described in the [document](). * Credentials conversion: * Convert legacy styled AnonCreds credentials into W3C form * Convert W3C styled AnonCreds credentials into legacy form - * Presentation conversion (Optional): + * Presentation conversion (Optional): * Convert legacy styled AnonCreds presentation into W3C form * Convert W3C styled AnonCreds presentation into legacy form +* Issue AnonCreds credentials in W3C form +* Create W3C presentations using W3C AnonCreds credentials +* Verify W3C presentations containing AnonCreds proof * 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 + * Ability to add additional credential metadata #### Out of scope * Credentials: Verify validity of non-AnonCreds Data Integrity proof signatures -* Presentations: Create presentation using non-AnonCreds Data Integrity proof signature +* Presentations: Create presentations using non-AnonCreds Data Integrity proof signature * Presentations: Verify validity of presentations including non-AnonCreds Data Integrity proof signatures * Presentations: Support different formats (for example DIF) of Presentation Request @@ -32,28 +36,34 @@ verifiable credential and presentation described in the [document](). * 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? - * Answer: No conversion for Credential Offer, Credential Request objects + * **Answer**: No conversion for Credential Offer, Credential Request objects. Existing types will be used. * 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. - * Answer: All methods will be duplicated + * **Answer:** + * All methods will be duplicated + * According to the Q1 answer `w3c_create_offer`, `w3c_create_request` methods will be returning the same object as original methods * Q3: Are we still tied to legacy 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. - * Answer: Keep API tied to existing AnonCreds Presentation Request format + * **Answer**: API methods will keep using an existing AnonCreds Presentation Request format * Q4: Do we want to provide general interfaces doing signing and verification of Non-AnonCreds 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 - * Answer: No. Third party libraries must be used for doing signing and verification of Non-AnonCreds Data Integrity proof signature + * **Answer:** No. + * Third party libraries must be used for doing signing and verification of Non-AnonCreds Data Integrity proof signature + * AnonCreds-rs only will only provide helper methods for setting attributes which can be needed for different Non-AnonCreds Data Integrity proof * Q5: Signature/Proof encoding: Which approach to use for encoding? * Basic approach used in Aries attachments: [BaseURL safe 64 encoding of object serialized as JSON string](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url)? * Compact encoding implemented in Python PoC: Using the fact that most fields of credential signature and proof are big numbers rather that strings. - * For example: the length of encoded credential signature string is about 2.5 times less than in the basic approach - * Find an [example data](./encoding.md#example) to see the difference - * Answer: Start from basic Aries encoding. Experiment with other algorithms as a next step. + * For example: the length of encoded credential signature string is about 2.5 times less than in the basic approach + * Find an [example data](./encoding.md#example) to see the difference + * **Answer**: + * Start from basic Aries encoding. + * Experiment with other algorithms (CBOR, Message Pack, Protobuf, Custom) as a next step. * Q6: W3C data model allows attributes to be represented not only as key/value string pairs but also as objects and arrays. * If we want to support more complex representations for the W3C AnonCreds credential attributes and their @@ -69,17 +79,20 @@ verifiable credential and presentation described in the [document](). } } ``` - * Answer: For current implementation we only support key/value string pairs + * **Answer**: + * Only key/value string pairs will be supported for the current phase * Q7: Should we care about back way conversion of credential issued in W3C form? * Assume that we issued W3C which cannot convert back into legacy 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 - * Answer: Yes. Within the current design/effort credentials must be convertible back and forth + * **Answer**: Yes. Within the current design/effort credentials must be convertible back and forth * Q8: Should we include Holder DID into credential subject as [`id` attribute](https://www.w3.org/TR/vc-data-model/#identifiers)? - * This enables credential subject [validation](https://www.w3.org/TR/vc-data-model/#credential-subject-0) - * We can add if for newly issued credentials but cannot set during the conversion of previously issued credentials. - * Answer: Up to Issuer, Optionally Issuer may include DID into credential subject + * This enables credential subject [validation](https://www.w3.org/TR/vc-data-model/#credential-subject-0) + * We can add if for newly issued credentials but cannot set during the conversion of previously issued credentials. + * **Answer**: + * Up to Issuer, Optionally Issuer may include DID into credential subject + * anoncreds-rs will provide a helper function to set `id` * Q9: 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) @@ -99,22 +112,29 @@ verifiable credential and presentation described in the [document](). ... } ``` - * Answer: Need more discussion + * **Answer**: Need more discussion * Q10: Should we remove `mapping` completely or move under encoded `proofValue`? - * Why `mapping` is bad: we make presentation tied to legacy styled Presentation Request - * Mapping is something old-fashioned synthetic required for doing validation (not signature verification) that proof matches to - the request itself on the verifier side - * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with - type) - * `revealed attributes` and `predicates` can be validated as we include them into `credentialSubject` but `unrevealed` attributes cannot. - + * Why `mapping` is bad: we make presentation tied to legacy styled Presentation Request + * Mapping is something old-fashioned synthetic required for doing validation (not signature verification) that proof matches to + the request itself on the verifier side + * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with + type) + * `revealed attributes` and `predicates` can be validated as we include them into `credentialSubject` but `unrevealed` attributes cannot. + * **Answer**: Need more discussion +* Q11: Revocation signature/proof: Should it be put into the same value of two independent signatures/proofs must be put into credential/presentation? +* Q12: For conversion of legacy credentials into W3C Credentials form we need to set `issuer_id` attribute. But legacy + credentials do not contain this field explicitly. `AnonCreds-rs` is designed to be ledger/DID method agnostic, so it + does not analyze/handle the values of id fields. + * How should we get issuer DID for putting into credential? + * Require `CredentialDefinition` to be passed as parameter + * Parse if `legacy` cred def id form is used ### Proposed implementation path for first iteration 1. Credential conversion APIs -2. Credential helper methods for non-AnonCreds integrity proof handling (set_integrity_proof, etc?) - * Generation and verification of non-AnonCreds 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 +2. Credential helper methods for non-AnonCreds integrity proof handling (set_integrity_proof, etc?) + * Generation and verification of non-AnonCreds 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: All methods 4. No adoption of Credential Offer and Credential Request objects for W3C standard 5. Keep API stick to existing Presentation Request format @@ -136,12 +156,11 @@ Methods purpose - have to forms of credentials (probably even duplicate in walle * `anoncreds_credential_from_w3c` - create a legacy styled presentation (for legacy Verifier) using a credential issued in W3C form ```rust -/// Convert legacy styled AnonCreds credential into W3C AnonCreds credential form -/// The conversion process described at the specification: --- +/// Convert credential in legacy form into W3C AnonCreds credential form /// /// # Params -/// cred - object handle pointing to legacy styled credential to convert -/// cred_p - reference that will contain converted credential (in W3C form) instance pointer +/// cred: object handle pointing to credential in legacy form to convert +/// cred_p: reference that will contain converted credential (in W3C form) instance pointer /// /// # Returns /// Error code @@ -151,12 +170,11 @@ pub extern "C" fn anoncreds_credential_to_w3c( cred_p: *mut ObjectHandle, ) -> ErrorCode {} -/// Convert W3C styled AnonCreds credential into legacy styled credential -/// The conversion process described at the specification: --- +/// Convert credential in W3C form into legacy credential form /// /// # Params -/// cred - object handle pointing to W3C styled AnonCreds credential to convert -/// cred_p - reference that will contain converted credential (in legacy form) instance pointer +/// cred: object handle pointing to credential in W3C form to convert +/// cred_p: reference that will contain converted credential (in legacy form) instance pointer /// /// # Returns /// Error code @@ -170,18 +188,52 @@ pub extern "C" fn anoncreds_credential_from_w3c( #### Credential object helper methods ```rust -/// Set Data Integrity proof signature for W3C AnonCreds credential +/// Add Non-Anoncreds Data Integrity proof signature to W3C AnonCreds credential /// /// # Params /// cred - object handle pointing to W3C AnonCreds credential -/// proof - data integrity proof signature as JSON string +/// proof - data integrity proof as JSON string +/// cred_p: reference that will contain update credential /// /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_credential_set_integrity_proof( +pub extern "C" fn anoncreds_w3c_credential_add_non_anoncreds_integrity_proof( cred: ObjectHandle, proof: FfiStr, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} + +/// Add context to W3C AnonCreds credential +/// +/// # Params +/// cred - object handle pointing to W3C AnonCreds credential +/// context - context to add into credential +/// cred_p: reference that will contain update credential +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_add_context( + cred: ObjectHandle, + context: FfiStr, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} + +/// Add type to W3C AnonCreds credential +/// +/// # Params +/// cred - object handle pointing to W3C AnonCreds credential +/// type - type to add into credential +/// cred_p: reference that will contain update credential +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_add_type( + cred: ObjectHandle, + type_: FfiStr, + cred_p: *mut ObjectHandle, ) -> ErrorCode {} ``` @@ -235,8 +287,8 @@ So the credentials and presentations themselves are generated using new flow met > 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`. +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: @@ -259,16 +311,13 @@ The reasons for adding duplication methods: ```rust /// Create Credential Offer according to the AnonCreds specification -/// It can be either legacy styled or W3C adopted depending on the answer for Q1 -/// If legacy styled credential to be used, it should indicate that credential in W3C AnonCreds form will be issued as the result. -/// -/// Even if we do not change Credential Offer message itself we start from using a separate set of API functions +/// Note that Credential Offer still will be legacy styled (the same as result of anoncreds_create_credential_offer) /// /// # Params /// schema_id: id of schema future credential refers to /// cred_def_id: id of credential definition future credential refers to /// key_proof: object handle pointing to credential definition key correctness proof -/// cred_offer_p - Reference that will contain created credential offer (in legacy form) instance pointer. +/// cred_offer_p: reference that will contain created credential offer (in legacy form) instance pointer /// /// # Returns /// Error code @@ -281,10 +330,7 @@ pub extern "C" fn anoncreds_w3c_create_credential_offer( ) -> ErrorCode {} /// Create Credential Request according to the AnonCreds specification -/// It can be either legacy styled or W3C adopted depending on the answer for Q1 -/// If legacy styled credential to be used, it should indicate that credential in W3C AnonCreds form will be issued as the result. -/// -/// Even if we do not change Credential Request message itself we start from using a separate set of API functions +/// Note that Credential Request still will be legacy styled (the same as result of anoncreds_create_credential_request) /// /// # Params /// entropy: entropy string to use for request creation @@ -310,16 +356,17 @@ pub extern "C" fn anoncreds_w3c_create_credential_request( cred_req_meta_p: *mut ObjectHandle, ) -> ErrorCode {} -/// Create W3C styled Credential according to the specification. +/// Create Credential in W3C form according to the specification. /// /// # Params -/// cred_def: object handle pointing to the credential definition -/// cred_def_private: object handle pointing to the private part of credential definition +/// cred_def: object handle pointing to the credential definition +/// cred_def_private: object handle pointing to the private part of credential definition /// cred_offer: object handle pointing to the credential offer /// cred_request: object handle pointing to the credential request /// attr_names: list of attribute names -/// attr_raw_values: list of attribute values -/// revocation: object handle pointing to the credential revocation data +/// attr_raw_values: list of attribute raw values +/// encoding: encoding algorithm to apply for attribute values +/// revocation: object handle pointing to the credential revocation info /// cred_p: reference that will contain credential (in W3C form) instance pointer /// /// # Returns @@ -332,6 +379,7 @@ pub extern "C" fn anoncreds_w3c_create_credential( cred_request: ObjectHandle, attr_names: FfiStrList, attr_raw_values: FfiStrList, + encoding: FfiStr, revocation: *const FfiCredRevInfo, cred_p: *mut ObjectHandle, ) -> ErrorCode {} @@ -339,13 +387,11 @@ pub extern "C" fn anoncreds_w3c_create_credential( /// Process an incoming W3C credential received from the issuer. /// /// # Params -/// cred_def: object handle pointing to the credential definition -/// cred_def_private: object handle pointing to the private part of credential definition -/// cred_offer: object handle pointing to the credential offer -/// cred_request: object handle pointing to the credential request -/// attr_names: list of attribute names -/// attr_raw_values: list of attribute values -/// revocation: object handle pointing to the credential revocation data +/// cred: object handle pointing to the credential in W3C form +/// cred_req_metadata: object handle pointing to the credential request metadata +/// link_secret: holder link secret +/// cred_def: object handle pointing to the credential definition +/// rev_reg_def: object handle pointing to the revocation registry definition /// cred_p: reference that will contain credential (in W3C form) instance pointer /// /// # Returns @@ -360,7 +406,7 @@ pub extern "C" fn anoncreds_w3c_process_credential( cred_p: *mut ObjectHandle, ) -> ErrorCode {} -/// Get value of request credential attribute as string +/// Get value of requested credential attribute as string /// /// # Params /// cred_def: object handle pointing to the credential (in W3 form) @@ -376,11 +422,10 @@ pub extern "C" fn anoncreds_w3c_credential_get_attribute( result_p: *mut *const c_char, ) -> ErrorCode {} -/// Create W3C styled Presentation according to the specification. +/// Create W3C Presentation according to the specification. /// -/// TODO: Function parameters need to be reworked if we decide to make it Presentation Request format agnostic -/// /// # Params +/// pres_req: object handle pointing to presentation request /// credentials: credentials (in W3C form) to use for presentation preparation /// credentials_prove: attributes and predicates to prove per credential /// link_secret: holder link secret @@ -394,6 +439,7 @@ 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, link_secret: FfiStr, @@ -404,12 +450,11 @@ pub extern "C" fn anoncreds_w3c_create_presentation( presentation_p: *mut ObjectHandle, ) -> ErrorCode {} -/// Create W3C styled Presentation according to the specification. -/// -/// TODO: Function parameters need to be reworked if we decide to make it Presentation Request format agnostic +/// Verity W3C styled Presentation /// /// # Params /// presentation: object handle pointing to presentation +/// pres_req: object handle pointing to presentation request /// schemas: list of credential schemas /// schema_ids: list of schemas ids /// cred_defs: list of credential definitions @@ -425,6 +470,7 @@ pub extern "C" fn anoncreds_w3c_create_presentation( #[no_mangle] pub extern "C" fn anoncreds_w3c_verify_presentation( presentation: ObjectHandle, + pres_req: ObjectHandle, schemas: FfiList, schema_ids: FfiStrList, cred_defs: FfiList, @@ -439,8 +485,6 @@ pub extern "C" fn anoncreds_w3c_verify_presentation( ### Demo scripts -> IN PROGRESS - #### Issue legacy Credential and present W3C Presentation ``` @@ -514,7 +558,7 @@ w3c_credential = Holder.anoncreds_w3c_process_credential(w3c_credential,...) /// Add RSA Identity Proof signature to credential integrity_proof = extartnal_library.create_rsa_integrity_proof(w3c_credential) -w3c_credential.set_integrity_proof(integrity_proof) +w3c_credential = anoncreds_w3c_credential_add_non_anoncreds_integrity_proof(w3c_credential, integrity_proof) /// Do wallets need to store both credential forms to handle legacy and DIF presentations requests? Wallet.store_w3c_credential(w3c_credential) @@ -523,4 +567,5 @@ Wallet.store_w3c_credential(w3c_credential) w3c_presentation_request = Verifier.w3c_create_presentation_request() rsa_integrity_proof_presentation = extartnal_library.create_presentation_using_rsa_integrity_proof(w3c_presentation_request, w3c_credential) extartnal_verifier.verify_rsa_integrity_proof_presentation(rsa_integrity_proof_presentation) -``` \ No newline at end of file +``` + From 11795bd4e7de1869730727f3ce9c8ae33f5f50e0 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Fri, 10 Nov 2023 15:33:41 +0300 Subject: [PATCH 07/13] Added section with example how we can deal if we drop mapping Signed-off-by: artem.ivanov --- docs/design/w3c/spec.md | 46 +------ docs/design/w3c/w3c-representation.md | 177 ++++++++++++++++++++++++++ tests/anoncreds_demos.rs | 1 + 3 files changed, 184 insertions(+), 40 deletions(-) diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md index 12ac0224..2c3bce06 100644 --- a/docs/design/w3c/spec.md +++ b/docs/design/w3c/spec.md @@ -313,26 +313,9 @@ Example of an AnonCreds W3C presentation which will be explained in details: "proof": { "type": "AnonCredsPresentationProof2023", "mapping": { - "revealedAttributes": [ - { - "name": "firstName", - "referent": "attribute_0" - } - ], - "unrevealedAttributes": [ - { - "name": "lastName", - "referent": "attribute_1" - } - ], - "requestedPredicates": [ - { - "name": "age", - "p_type": "<", - "value": 18, - "referent": "predicate_1" - } - ] + "revealedAttributes": ["attribute_0"], + "unrevealedAttributes": ["attribute_1"], + "requestedPredicates": ["predicate_1"] }, "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" } @@ -410,26 +393,9 @@ type pointing to the difference in a presentation structure and looks the follow "proof": { "type": "AnonCredsPresentationProof2023", "mapping": { - "revealedAttributes": [ - { - "name": "firstName", - "referent": "attribute_0" - } - ], - "unrevealedAttributes": [ - { - "name": "lastName", - "referent": "attribute_1" - } - ], - "requestedPredicates": [ - { - "name": "age", - "p_type": "<", - "value": 18, - "referent": "predicate_1" - } - ] + "revealedAttributes": ["attribute_0"], + "unrevealedAttributes": ["attribute_1"], + "requestedPredicates": ["predicate_1"] }, "timestamp": Option<1234567>, "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw"**** diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 9cac6078..0e831558 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -569,3 +569,180 @@ rsa_integrity_proof_presentation = extartnal_library.create_presentation_using_r extartnal_verifier.verify_rsa_integrity_proof_presentation(rsa_integrity_proof_presentation) ``` +### Presentation validation + +**Request** +``` +{ + "name":"pres_req_1", + "non_revoked":null, + "nonce":"358493544514389191968232", + "requested_attributes":{ + "attr1_referent":{ + "name":"first_name", + "non_revoked":null, + "restrictions":null + }, + "attr2_referent":{ + "name":"sex", + "non_revoked":null, + "restrictions":null + }, + "attr3_referent":{ + "names":[ + "last_name", + "height" + ], + "non_revoked":null, + "restrictions":null + } + }, + "requested_predicates":{ + "predicate1_referent":{ + "name":"age", + "non_revoked":null, + "p_type":">=", + "p_value":18, + "restrictions":null + } + }, + "ver":"1.0", + "version":"0.1" +} +``` + +**Presentation** +``` +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" + ], + "type": [ + "VerifiablePresentation", + "AnonCredsPresentation" + ], + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" + ], + "type": [ + "VerifiableCredential", + "AnonCredsPresentation" + ], + "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", + "issuanceDate": "2023-10-26T01:17:32Z", + "credentialSchema": { + "type": "AnonCredsDefinition", + "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", + "encoding": "auto" + }, + "credentialSubject": { + "first_name": "Alice" + "lastt_name": "Jons" + "height": "185" + }, + "proof": { + "type": "AnonCredsPresentationProof2023", + "mapping": { + "revealedAttributes": ["attr1_referent"], + "unrevealedAttributes": ["attr2_referent"], + "revealedAttributeGroups": ["attr3_referent"], + "requestedPredicates": ["predicate1_referent"] + }, + "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" + } + } + ], + "proof": { + "type": "AnonCredsPresentationProof2023", + "challenge": "182453895158932070575246", + "proofValue": "AAAgtMR4....J19l-agSA" + } +} +``` + +**Verifier validation steps is we keep mapping**: +``` +// validate requested attributes +for (referent, requested) in presentation_request.requested_attributes { + credential = presentation.verifiableCredential.find((verifiableCredential) => + verifiableCredential.proof.mapping.revealedAttributes.includes(referent) || + verifiableCredential.proof.mapping.unrevealedAttributes.includes(referent) || + verifiableCredential.proof.mapping.revealedAttributeGroups.includes(referent)) + + credential.checkRestrictions(requested.restrictions) + + if !credential { + error + } + if requested.name { + assert(credential.credentialSubject[requested.name]) + } + if requested.names { + names.forEach((name) => assert(credential.credentialSubject[name])) + } +} + +// validate requested predicates +for (referent, requested) in presentation_request.requested_predicates { + credential = presentation.verifiableCredential.find((verifiableCredential) => + verifiableCredential.proof.mapping.requestedPredicates.includes(referent)) + credential.checkRestrictions(requested.restrictions) + assert(credential.credentialSubject[requested.name]) // if we include derived predicate into subject +} +``` + +**Verifier validation steps is we drop mapping**: +``` +// validate requested attributes +for (referent, requested) in presentation_request.requested_attributes { + if requested.name { + // or filter if requted same attribute multiple times? + credential = presentation.verifiableCredential.find((verifiableCredential) => + credentialSubject.contains(requested[name]) + ) + if credential { + credential.checkRestrictions(requested.restrictions) + assert(credential.credentialSubject[requested.name]) + } + if !credential { + // consider attribute as unrevealed + // If we need to support and validate unrevealed attributes + credential_with_attribute = presentation.verifiableCredential.find((verifiableCredential) => + schema = get_schema(verifiableCredential.schema_id) // all schemas already passed into verification function + schema.attributes.includes(requested.name) + verifiableCredential.matches(restrictions) + ) + if !credential_with_attribute { + error + } + } + } + if requested.names { + for (referent, requested) in requested.names { + // do same as for single attribute above + // make sure that all come from single credential + } + } +} + +// validate requested predicates - we put predicate derived string or object into credentialSubject +// { +// "age" ">= 18" +// } +for (referent, requested) in presentation_request.requested_predicates { + // or filter if requted same attribute multiple times? + credential = presentation.verifiableCredential.find((verifiableCredential) => + credentialSubject.contains(requested[name]) + ) + if !credential { + error + } + credential.checkRestrictions(requested.restrictions) + assert(credential.credentialSubject[requested.name]) +} +``` \ No newline at end of file diff --git a/tests/anoncreds_demos.rs b/tests/anoncreds_demos.rs index beef89a2..7ffadb62 100644 --- a/tests/anoncreds_demos.rs +++ b/tests/anoncreds_demos.rs @@ -2808,6 +2808,7 @@ fn anoncreds_works_for_restrictions_as_empty_array() { let rev_reg_defs_json = json!({}).to_string(); let rev_regs_json = json!({}).to_string(); + let valid = anoncreds::verifier_verify_proof( &proof_req_json, &proof_json, From 57b8912752eda54516f92d97b7af28931a55cd35 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Mon, 13 Nov 2023 17:04:41 +0300 Subject: [PATCH 08/13] Updated names of functions Signed-off-by: artem.ivanov --- docs/design/w3c/w3c-representation.md | 46 +++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 0e831558..0589112d 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -128,6 +128,8 @@ verifiable credential and presentation described in the [document](). * How should we get issuer DID for putting into credential? * Require `CredentialDefinition` to be passed as parameter * Parse if `legacy` cred def id form is used +* Q13: Issuance data: W3C specification requires setting of `issuanceDate` property to express the date and time when a credential becomes valid. + * What datetime should we use? current / random of the day / start of the day ### Proposed implementation path for first iteration @@ -235,6 +237,38 @@ pub extern "C" fn anoncreds_w3c_credential_add_type( type_: FfiStr, cred_p: *mut ObjectHandle, ) -> ErrorCode {} + +/// Set subject id to W3C AnonCreds credential +/// +/// # Params +/// cred - object handle pointing to W3C AnonCreds credential +/// id - subject id to add into credential +/// cred_p: reference that will contain update credential +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_set_subject_id( + cred: ObjectHandle, + id: FfiStr, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} + +/// Set id to W3C AnonCreds credential +/// +/// # Params +/// cred - object handle pointing to W3C AnonCreds credential +/// id - id to add into credential +/// cred_p: reference that will contain update credential +/// +/// # Returns +/// Error code +#[no_mangle] +pub extern "C" fn anoncreds_w3c_credential_id( + cred: ObjectHandle, + id: FfiStr, + cred_p: *mut ObjectHandle, +) -> ErrorCode {} ``` #### Optional: Presentation Conversion methods @@ -322,7 +356,7 @@ The reasons for adding duplication methods: /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_create_credential_offer( +pub extern "C" fn anoncreds_create_w3c_credential_offer( schema_id: FfiStr, cred_def_id: FfiStr, key_proof: ObjectHandle, @@ -345,7 +379,7 @@ pub extern "C" fn anoncreds_w3c_create_credential_offer( /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_create_credential_request( +pub extern "C" fn anoncreds_create_w3c_credential_request( entropy: FfiStr, prover_did: FfiStr, cred_def: ObjectHandle, @@ -372,7 +406,7 @@ pub extern "C" fn anoncreds_w3c_create_credential_request( /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_create_credential( +pub extern "C" fn anoncreds_create_w3c_credential( cred_def: ObjectHandle, cred_def_private: ObjectHandle, cred_offer: ObjectHandle, @@ -397,7 +431,7 @@ pub extern "C" fn anoncreds_w3c_create_credential( /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_process_credential( +pub extern "C" fn anoncreds_process_w3c_credential( cred: ObjectHandle, cred_req_metadata: ObjectHandle, link_secret: FfiStr, @@ -438,7 +472,7 @@ pub extern "C" fn anoncreds_w3c_credential_get_attribute( /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_create_presentation( +pub extern "C" fn anoncreds_create_w3c_presentation( pres_req: ObjectHandle, credentials: FfiList, credentials_prove: FfiList, @@ -468,7 +502,7 @@ pub extern "C" fn anoncreds_w3c_create_presentation( /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_verify_presentation( +pub extern "C" fn anoncreds_verify_w3c_presentation( presentation: ObjectHandle, pres_req: ObjectHandle, schemas: FfiList, From 50215ca61b107383b57b713ff4c14458b7d9a965 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Mon, 13 Nov 2023 20:59:53 +0300 Subject: [PATCH 09/13] Add answer for the rest of questions Signed-off-by: artem.ivanov --- docs/design/w3c/w3c-representation.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 0589112d..bd69b4e2 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -120,16 +120,20 @@ verifiable credential and presentation described in the [document](). * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with type) * `revealed attributes` and `predicates` can be validated as we include them into `credentialSubject` but `unrevealed` attributes cannot. - * **Answer**: Need more discussion + * **Answer**: Drop `mapping` - see at the bottom of the document an example on how the validation of verifier's side still can be done * Q11: Revocation signature/proof: Should it be put into the same value of two independent signatures/proofs must be put into credential/presentation? + * **Answer**: For the current implementation it's good just to put everything inside encoded proof value + * For future: Prepare a section example describing how non revocation can be extracted into a separate proof * Q12: For conversion of legacy credentials into W3C Credentials form we need to set `issuer_id` attribute. But legacy credentials do not contain this field explicitly. `AnonCreds-rs` is designed to be ledger/DID method agnostic, so it does not analyze/handle the values of id fields. * How should we get issuer DID for putting into credential? * Require `CredentialDefinition` to be passed as parameter * Parse if `legacy` cred def id form is used + * **Answer**: Require passing credential definition as parameter * Q13: Issuance data: W3C specification requires setting of `issuanceDate` property to express the date and time when a credential becomes valid. - * What datetime should we use? current / random of the day / start of the day + * What datetime should we use? current / random of the day / start of the day + * **Answer**: It's ok just to use the current time ### Proposed implementation path for first iteration From eba2c42c3301055f002d58bf7a7f764171ceffab Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Thu, 16 Nov 2023 11:10:25 +0300 Subject: [PATCH 10/13] Removed documents which we moved to anoncreds-spec repo Signed-off-by: artem.ivanov --- docs/design/w3c/context.json | 77 ----- docs/design/w3c/spec.md | 463 -------------------------- docs/design/w3c/w3c-representation.md | 101 ++++++ tests/anoncreds_demos.rs | 1 - 4 files changed, 101 insertions(+), 541 deletions(-) delete mode 100644 docs/design/w3c/context.json delete mode 100644 docs/design/w3c/spec.md diff --git a/docs/design/w3c/context.json b/docs/design/w3c/context.json deleted file mode 100644 index 9e31c2f2..00000000 --- a/docs/design/w3c/context.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "@context": { - "@version": 1.1, - "@protected": true, - "ac": "https://anoncreds.example/2022/ns#", - "xsd": "http://www.w3.org/2001/XMLSchema#", - - "AnonCredsCredential": "ac:AnonCredsCredential", - - "AnonCredsDefinition": { - "@id": "ac:AnonCredsDefinition", - "@context": { - "@version": 1.1, - "@protected": true, - "definition": { - "@id": "ac:definition", - "@type": "@id" - }, - "schema": { - "@id": "ac:schema", - "@type": "@id" - }, - "revocation_registry": { - "@id": "ac:revocation_registry", - "@type": "@id" - }, - "encoding": { - "@id": "ac:attributeEncoding", - "@type": "@vocab", - "@context": { - "@version": 1.1, - "@protected": true, - "auto": "ac:autoEncoding" - } - } - } - }, - - "AnonCredsPresentation": "ac:AnonCredsPresentation", - - "AnonCredsPresentationProof2022": { - "@id": "ac:AnonCredsPresentationProof2022", - "@context": { - "@version": 1.1, - "@protected": true, - "mapping": { - "@id": "ac:attributeMapping", - "@type": "@json" - }, - "timestamp": { - "@id": "ac:timestamp", - "@type": "xsd:decimal" - }, - "proofValue": { - "@id": "ac:proofValue", - "@type": "xsd:string" - }, - "challenge": { - "@id": "ac:challenge", - "@type": "xsd:string" - } - } - }, - - "CLSignature2023": { - "@id": "ac:CLSignature2023", - "@context": { - "@version": 1.1, - "@protected": true, - "signature": { - "@id": "ac:signature", - "@type": "xsd:string" - } - } - } - } -} diff --git a/docs/design/w3c/spec.md b/docs/design/w3c/spec.md deleted file mode 100644 index 2c3bce06..00000000 --- a/docs/design/w3c/spec.md +++ /dev/null @@ -1,463 +0,0 @@ -## W3C Verifiable Credentials Representation - -This section describes how legacy AnonCreds credentials can be represented in the form of W3C Verifiable -Credentials standard. - -### Credential - -This section describes how [W3C credential concepts](https://www.w3.org/TR/vc-data-model/#basic-concepts) are applied to -AnonCreds W3C credential representation. - -Example of an AnonCreds W3C formatted credential which will be explained in details: - -```json -{ - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" - ], - "type": [ - "VerifiableCredential", - "AnonCredsCredential" - ], - "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", - "issuanceDate": "2023-10-26T01:17:32Z", - "credentialSchema": { - "type": "AnonCredsDefinition", - "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", - "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", - "encoding": "auto" - }, - "credentialSubject": { - "firstName": "Alice", - "lastName": "Jones", - "age": "18" - }, - "proof": [ - { - "type": "CLSignature2023", - "signature": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM" - }, - { - "type": "Ed25519Signature2020", - "created": "2021-11-13T18:19:39Z", - "verificationMethod": "did:sov:3avoBCqDMFHFaKUHug9s8W#key-1", - "proofPurpose": "assertionMethod", - "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" - } - ] -} -``` - -#### Context - -W3C [Context](https://www.w3.org/TR/vc-data-model/#contexts) section requires including of `@context` property to -verifiable credential. - -The value of the `@context` property must be one or more resolvable [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) -that result in machine-readable [JSON-LD](https://www.w3.org/TR/vc-data-model/#json-ld) information about the object -format. - -The **context** definition used for AnonCreds W3C credentials representation can be found [here](./context.json). - -In the case of W3C AnonCreds credentials, the `@context` attribute includes an extra -entry `https://github.io/anoncreds-w3c/context.json` -which is required for the resolution of custom structure definitions and looks the following: - -``` -{ - ... - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://github.io/anoncreds-w3c/context.json" - ], - ... -} -``` - -#### Identifiers - -W3C [Identifiers](https://www.w3.org/TR/vc-data-model/#identifiers) section defines an optional capability to assign -some kind of identifier to the verifiable credential so that others can express statements about the same thing. - -In the case of W3C AnonCreds credentials, the `id` attribute is not recommended to set. - -#### Types - -W3C [Types](https://www.w3.org/TR/vc-data-model/#types) section requires including of `type` property to verifiable -credential. -The value of the `type` property must be one or more [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) resolvable -through the defined `@context` to the information required for determining whether a verifiable credential or verifiable -presentation has a valid structure. - -In the case of W3C AnonCreds credentials, the `type` attribute includes an extra entry `AnonCredsCredential` -pointing to the difference in a base credential structure and looks the following: - -``` -{ - ... - "type": [ - "VerifiableCredential", // general verifiable credential definition - "AnonCredsCredential", // definition for AnonCreds credentials - ] - ... -} -``` - -#### Credential Subject - -W3C [Credential Subject](https://www.w3.org/TR/vc-data-model/#credential-subject) section requires including -of `credentialSubject` property to verifiable credential. - -Credential subject value contains [claims](https://www.w3.org/TR/vc-data-model/#claims) about one or more subjects. - -In the context of W3C Announced credentials, credential subject property is compliant with the following statements: - -- credentials will always include claims about only one subjects. - - So that `credentialSubject` property will always be represented as an object entry, but not an array. -- credentials claims are always represented as key value pairs, where `value` is the `raw` value of CL credential - attributes. - - encoded CL credential values are not included in the credential subject - -In the case of W3C AnonCreds credentials, the `credentialSubject` attribute looks the following: - -``` -{ - ... - "credentialSubject": { - "name": "Alice Jones", - } - ... -} -``` - -#### Data Schemas - -W3C [Credential Subject](https://www.w3.org/TR/vc-data-model/#data-schemas) section defines an optional capability to -include `credentialSchema` property to enforce a specific structure on a given verifiable credential and encoding used -to map the claims of a verifiable credential to an alternative representation format. - -In the context of W3C AnonCreds credentials defined a custom `AnonCredsDefinition` data schema in order to include the -following information to credential: - -In the case of W3C AnonCreds credentials, the `credentialSchema` attribute defines a custom `AnonCredsDefinition` -schema in order to include the information about AnonCreds related definitions to credential and looks the following: - -``` -{ - ... - "credentialSchema": { - "type": "AnonCredsDefinition", - "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", - "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:fabername:0.1.0", - "encoding": "auto" - }, - ... -} -``` - -* `schema` - id of AnonCreds Schema -* `definition` - id of AnonCreds Credential Definition -* `revocation_registry` - (Optional) id of AnonCreds Revocation Registry -* `encoding` - attributes encoding algorithm - * encoded credential attribute values (binary representation required for doing CL signatures) are not included - neither to `credentialSubject` or `signature` - * `encoding: auto` implies using the algorithm defined - at [Aries RFC 0592 Indy Attachments section](https://github.com/hyperledger/aries-rfcs/tree/main/features/0592-indy-attachments#encoding-claims) - to generate encoded values under the hood during the signature generation and proof verification. - -#### Issuer - -W3C [Issuer](https://www.w3.org/TR/vc-data-model/#issuer) section requires including of `issuer` property to express the -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/) and looks the following: - -``` -{ - ... - "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", - ... -} -``` - -#### Issuance Date - -W3C [Issuance Date](https://www.w3.org/TR/vc-data-model/#issuance-date) section requires including of `issuanceDate` -property to express the date and time when a credential becomes valid. - -In the case of W3C AnonCreds credentials, for the `issuanceDate` attribute recommended setting of a random time of the -day when credential was issued or transformed and looks the following: - -``` -{ - ... - "issuanceDate": "2010-01-01T19:23:24Z", - ... -} -``` - -#### Proofs (Signatures) - -W3C [Proofs (Signatures)](https://www.w3.org/TR/vc-data-model/#proofs-signatures) section requires including of `proof` -property to express confirmation of the credential's validity. - -According to the specification, one or many proof objects can be added to verifiable credentials. -In the context of W3C AnonCreds credentials included at least two proof object entries: AnonCreds CL -and [Data Integrity](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs). - -##### AnonCreds CL proof - -This proof entry derived from the CL signature of a verifiable credential. - -The defined `@context` includes a definition for the `CLSignature2022` type describing the format of the proof -entry: - -``` -{ - ... - "proof": [ - { - "type": "CLSignature2022", - "signature": "AAAgf9w5lZg....RYp8Z_x3FqdwRHoWruiF0FlM" - } - ] - ... -} -``` - -**Credential proof signature** - -* `type` - `CLSignature2022` -* `signature` - credential signature - * signature received by building the following object: - ``` - { - "signature": {..}, - "signature_correctness_proof": {..}, - "rev_reg": Option<{..}>, - "witness": Option<{..}>, - } - ``` - * encoded - as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url) - -> Note that `rev_reg` and `witness` are only should be set in Issuer's signature. -> After processing the credential signature on the Holder's side these data can be cleaned to reduce the credential size - -##### non-AnonCreds Integrity proof - -In order to better conform to the W3C specification AnonCreds based credential also allow including -of non-AnonCreds [Data Integrity Proof](https://www.w3.org/TR/vc-data-model/#data-integrity-proofs) which must be -generated using one -of NIST-approved algorithms (RSA, ECDSA, EdDSA). - -#### Expiration - -W3C [Expiration](https://www.w3.org/TR/vc-data-model/#expiration) section defines an optional capability to include -credential expiration information. - -Instead of including `expirationDate` property we recommend using a standard AnonCreds credentials revocation approach -and -include a revocation registry id into the credential schema. - -#### Status - -W3C [Status](https://www.w3.org/TR/vc-data-model/#status) section defines an optional capability to include credential -status information. - -Instead of including `credentialStatus` property we recommend using a standard AnonCreds credentials revocation approach -and -include a revocation registry id into the credential schema. - -### Presentation - -This section describes how [W3C presentation concepts](https://www.w3.org/TR/vc-data-model/#contexts) are applied to -AnonCreds -W3C presentation representation. - -Example of an AnonCreds W3C presentation which will be explained in details: - -```json -{ - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" - ], - "type": [ - "VerifiablePresentation", - "AnonCredsPresentation" - ], - "verifiableCredential": [ - { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" - ], - "type": [ - "VerifiableCredential", - "AnonCredsPresentation" - ], - "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", - "issuanceDate": "2023-10-26T01:17:32Z", - "credentialSchema": { - "type": "AnonCredsDefinition", - "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", - "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", - "encoding": "auto" - }, - "credentialSubject": { - "firstName": "Alice" - }, - "proof": { - "type": "AnonCredsPresentationProof2023", - "mapping": { - "revealedAttributes": ["attribute_0"], - "unrevealedAttributes": ["attribute_1"], - "requestedPredicates": ["predicate_1"] - }, - "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw" - } - } - ], - "proof": { - "type": "AnonCredsPresentationProof2023", - "challenge": "182453895158932070575246", - "proofValue": "AAAgtMR4....J19l-agSA" - } -} -``` - -#### Context - -W3C [Context](https://www.w3.org/TR/vc-data-model/#contexts) section requires including of `@context` property to -verifiable presentation. -The value of the `@context` property must be one or more resolvable [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) -that result in machine-readable [JSON-LD](https://www.w3.org/TR/vc-data-model/#json-ld) information about the object -format. - -The complete **context** containing definitions used for AnonCreds W3C credentials representation can be -found [here](./context.json). - -In the case of W3C AnonCreds presentations, the `@context` attribute includes an extra -entry `https://github.io/anoncreds-w3c/context.json` -which is required for the resolution of custom structure definitions and looks the following: - -``` -{ - ... - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://github.io/anoncreds-w3c/context.json" - ], - ... -} -``` - -#### Types - -W3C [Types](https://www.w3.org/TR/vc-data-model/#types) section requires including of `type` property to verifiable -presentation. -The value of the `type` property must be one or more [URI](https://www.w3.org/TR/vc-data-model/#dfn-uri) resolvable -through the defined `@context` to the information required for determining whether a verifiable -presentation has a valid structure. - -In the case of W3C AnonCreds presentations, the `type` attribute includes an extra entry `AnonCredsPresentation` -pointing to the difference in a base presentation structure and looks the following: - -``` -{ - ... - "type": [ - "VerifiablePresentation", // general verifiable presentation definition - "AnonCredsPresentation" // definition for AnonCreds presentation - ] - ... -} -``` - -#### Verifiable Credential - -W3C [Verifiable Credential](https://www.w3.org/TR/vc-data-model/#presentations-0)section requires including -of `verifiableCredential` property to a verifiable presentation constructed from one or more verifiable credentials. - -The values of verifiable credentials are mostly constructed the same as described at -the [Credential Structure](#credential) section. -The only difference is the value of the `proof` property. - -In the case of W3C AnonCreds presentations, the `proof` attribute uses defined `AnonCredsPresentationProof2023` -type pointing to the difference in a presentation structure and looks the following: - -``` - "proof": { - "type": "AnonCredsPresentationProof2023", - "mapping": { - "revealedAttributes": ["attribute_0"], - "unrevealedAttributes": ["attribute_1"], - "requestedPredicates": ["predicate_1"] - }, - "timestamp": Option<1234567>, - "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw"**** - } -``` - -**Verifiable Credential Proof structure** - -* `proofValue` - encoded proof generated for each specific credential - * proof value received by building the following object: - ``` - { - sub_proof: {..} - } - ``` - * encoded - as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url). -* `mapping` - date requested in the proof request - * data: attribute name and reference in the proof request - * `revealedAttributes` - list of requested attributes revealed using the credential - * `unrevealedAttributes` - list of requested attributes presented in the credential but left unrevealed - * `requestedPredicates` - list of predicates resolved using the credential -* `timestamp` - (Optional) if revocation supported and requested, time as a total number of seconds from Unix Epoch - representing pointing to the specif moment of revocation registry - -#### Proof - -W3C [Proofs (Signatures)](https://www.w3.org/TR/vc-data-model/#proofs-signatures) section requires including of `proof` -property to express confirmation of the presentation's validity. - -As we described in the above section verifiable credentials will contain two proof entries (CL AnonCreds of Data -Integrity). -Unlike verifiable credentials, a presentation can contain only one proof object. - -It is verifier and holder responsibility to negotiate which proof must be used (CL AnonCreds of Data Integrity) in the -presentation: - -* Generate an W3C AnonCreds presentation, with all it’s privacy-preserving power and predicates -* Present the VC using one of non-AnonCreds Integrity Proof Signatures - -``` -{ - ... - "proof": { - "type": "AnonCredsPresentationProof2023", - "challenge": "182453895158932070575246", - "proofValue": "AAAgtMR4DrkY--ZVgKHmUANE04ET7TzUxZ0vZmVcNt4nCkwBABUACQJ69kJVIxHVAQAIAaJ19l-agSA" - } - ... -} -``` - -**Presentation Proof structure** - -* `challenge` - nonce taken from the presentation request -* `aggregated` - encoded aggregated proof value - * proof value received by building the following object: - ``` - { - aggregated: {..}, - } - ``` - * encoded - as [base64 attachment](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url). - diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index bd69b4e2..943c8888 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -783,4 +783,105 @@ for (referent, requested) in presentation_request.requested_predicates { credential.checkRestrictions(requested.restrictions) assert(credential.credentialSubject[requested.name]) } +``` + +### Examples + +Example of an AnonCreds W3C credential: + +```json +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" + ], + "type": [ + "VerifiableCredential", + "AnonCredsCredential" + ], + "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", + "issuanceDate": "2023-10-26T01:17:32Z", + "credentialSchema": { + "type": "AnonCredsDefinition", + "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", + "encoding": "auto" + }, + "credentialSubject": { + "firstName": "Alice", + "lastName": "Jones", + "age": "18" + }, + "proof": [ + { + "type": "CLSignature2023", + "signature": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM" + }, + { + "type": "Ed25519Signature2020", + "created": "2021-11-13T18:19:39Z", + "verificationMethod": "did:sov:3avoBCqDMFHFaKUHug9s8W#key-1", + "proofPurpose": "assertionMethod", + "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" + } + ] +} +``` + +Example of an AnonCreds W3C presentation: + +```json +{ + "@context":[ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-spec/w3c-credentials/data/anoncreds-w3c-context.json" + ], + "type":[ + "VerifiablePresentation", + "AnonCredsPresentation" + ], + "verifiableCredential":[ + { + "@context":[ + "https://www.w3.org/2018/credentials/v1", + "https://raw.githubusercontent.com/DSRCorporation/anoncreds-spec/w3c-credentials/data/anoncreds-w3c-context.json" + ], + "type":[ + "VerifiableCredential", + "AnonCredsCredential" + ], + "credentialSchema": { + "type": "AnonCredsDefinition", + "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", + "encoding": "auto" + }, + "credentialSubject":{ + "firstName":"Alice", + "age":{ + "type":"AnonCredsPredicate", + "p_type":">=", + "p_value":18 + } + }, + "issuanceDate":"2023-11-15T10:59:48.036203Z", + "issuer":"issuer:id/path=bar", + "proof":{ + "type":"AnonCredsPresentationProof2023", + "mapping":{ + "predicates":["predicate1_referent"], + "revealedAttributeGroups":[], + "revealedAttributes":["attr1_referent"], + "unrevealedAttributes":[] + }, + "proofValue":"eyJzdWJfcHJvb2Yi...zMTc1NzU0NDAzNDQ0ODUifX1dfX19" + } + } + ], + "proof":{ + "type":"AnonCredsPresentationProof2023", + "challenge":"413296376279822794586260", + "proofValue":"eyJhZ2dyZWdhdGVkIjp7ImNfaGFzaCI6IjEwMT...IsMzAsMTM1LDE4MywxMDcsMTYwXV19fQ==" + } +} ``` \ No newline at end of file diff --git a/tests/anoncreds_demos.rs b/tests/anoncreds_demos.rs index 7ffadb62..beef89a2 100644 --- a/tests/anoncreds_demos.rs +++ b/tests/anoncreds_demos.rs @@ -2808,7 +2808,6 @@ fn anoncreds_works_for_restrictions_as_empty_array() { let rev_reg_defs_json = json!({}).to_string(); let rev_regs_json = json!({}).to_string(); - let valid = anoncreds::verifier_verify_proof( &proof_req_json, &proof_json, From 158548c44720c5316a012017b9caeb9702eb09f0 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Thu, 23 Nov 2023 14:42:30 +0300 Subject: [PATCH 11/13] Deleted document describing custom encoding Signed-off-by: artem.ivanov --- docs/design/w3c/encoding.md | 139 -------------------------- docs/design/w3c/w3c-representation.md | 1 - 2 files changed, 140 deletions(-) delete mode 100644 docs/design/w3c/encoding.md diff --git a/docs/design/w3c/encoding.md b/docs/design/w3c/encoding.md deleted file mode 100644 index 6fc86af4..00000000 --- a/docs/design/w3c/encoding.md +++ /dev/null @@ -1,139 +0,0 @@ -### Encoding - -As all fields of AnonCreds credential signature and proof objects are big numbers, the straight object JSON serialization and representing as bytes is not effective. -Instead, we propose using of an alternative algorithm, providing more compact representation, consisting of the following steps: - -Also, due to the fact that fields order matters during serialization/deserialization process, encoding must be applied to attributes in alphabetic order. - -> TO DISCUSS: For simplicity we still can use straight object JSON serialization and representing as bytes but the size of encoded string will be almost 3 times bigger. - -#### Example - -**Signature data:** -``` -{ - "m_2": "57832835556928742723946725004638238236382427793876617639158517726445069815397", - "a": "20335594316731334597758816443885619716281946894071547670112874227353349613733788033617671091848119624077343554670947282810485774124636153228333825818186760397527729892806528284243491342499262911619541896964620427749043381625203893661466943880747122017539322865930800203806065857795584699623987557173946111100450130555197585324032975907705976283592876161733661021481170756352943172201881541765527633833412431874555779986196454199886878078859992928382512010526711165717317294021035408585595567390933051546616905350933492259317172537982279278238456869493798937355032304448696707549688520575565393297998400926856935054785", - "e": "259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742930114221280625468933785621106476195767", - "v": "6264315754962089362691677910875768714719628097173834826942639456162861264780209679632476338104728648674666095282910717315628966174111516324733617604883927936031834134944562245348356595475949760140820205017843765225176947252534891385340037654527825604373031641665762232119470199172203915071879260274922482308419475927587898260844045340005759709509719230224917577081434498505999519246994431019808643717455525020238858900077950802493426663298211783820016830018445034267920428147219321200498121844471986156393710041532347890155773933440967485292509669092990420513062430659637641764166558511575862600071368439136343180394499313466692464923385392375334511727761876368691568580574716011747008456027092663180661749027223129454567715456876258225945998241007751462618767907499044716919115655029979467845162863204339002632523083819", - "se": "16380378819766384687299800964395104347426132415600670073499502988403571039552426989440730562439872799389359320216622430122149635890650280073919616970308875713611769602805907315796100888051513191790990723115153015179238215201014858697020476301190889292739142646098613335687696678474499610035829049097552703970387216872374849734708764603376911608392816067509505173513379900549958002287975424637744258982508227210821445545063280589183914569333870632968595659796744088289167771635644102920825749994200219186110532662348311959247565066406030309945998501282244986323336410628720691577720308242032279888024250179409222261839", - "c": "54687071895183924055442269144489786903186459631877792294627879136747836413523" -} -``` - -**Using [Aries base64 attachment encoding](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url):** -``` -// Length: 3260 -JtXzIiOiAiNTc4MzI4MzU1NTY5Mjg3NDI3MjM5NDY3MjUwMDQ2MzgyMzgyMzYzODI0Mjc3OTM4NzY2MTc2MzkxNTg1MTc3MjY0NDUwNjk4MTUzOTciLCAiYSI6ICIyMDMzNTU5NDMxNjczMTMzNDU5Nzc1ODgxNjQ0Mzg4NTYxOTcxNjI4MTk0Njg5NDA3MTU0NzY3MDExMjg3NDIyNzM1MzM0OTYxMzczMzc4ODAzMzYxNzY3MTA5MTg0ODExOTYyNDA3NzM0MzU1NDY3MDk0NzI4MjgxMDQ4NTc3NDEyNDYzNjE1MzIyODMzMzgyNTgxODE4Njc2MDM5NzUyNzcyOTg5MjgwNjUyODI4NDI0MzQ5MTM0MjQ5OTI2MjkxMTYxOTU0MTg5Njk2NDYyMDQyNzc0OTA0MzM4MTYyNTIwMzg5MzY2MTQ2Njk0Mzg4MDc0NzEyMjAxNzUzOTMyMjg2NTkzMDgwMDIwMzgwNjA2NTg1Nzc5NTU4NDY5OTYyMzk4NzU1NzE3Mzk0NjExMTEwMDQ1MDEzMDU1NTE5NzU4NTMyNDAzMjk3NTkwNzcwNTk3NjI4MzU5Mjg3NjE2MTczMzY2MTAyMTQ4MTE3MDc1NjM1Mjk0MzE3MjIwMTg4MTU0MTc2NTUyNzYzMzgzMzQxMjQzMTg3NDU1NTc3OTk4NjE5NjQ1NDE5OTg4Njg3ODA3ODg1OTk5MjkyODM4MjUxMjAxMDUyNjcxMTE2NTcxNzMxNzI5NDAyMTAzNTQwODU4NTU5NTU2NzM5MDkzMzA1MTU0NjYxNjkwNTM1MDkzMzQ5MjI1OTMxNzE3MjUzNzk4MjI3OTI3ODIzODQ1Njg2OTQ5Mzc5ODkzNzM1NTAzMjMwNDQ0ODY5NjcwNzU0OTY4ODUyMDU3NTU2NTM5MzI5Nzk5ODQwMDkyNjg1NjkzNTA1NDc4NSIsICJlIjogIjI1OTM0NDcyMzA1NTA2MjA1OTkwNzAyNTQ5MTQ4MDY5NzU3MTkzODI3Nzg4OTUxNTE1MjMwNjI0OTcyODU4MzEwNTY2NTgwMDcxMzMwNjc1OTE0OTk4MTY5MDU1OTE5Mzk4NzE0MzAxMjM2NzkxMzIwNjI5OTMyMzg5OTY5Njk0MjIxMzIzNTk1Njc0MjkzMDExNDIyMTI4MDYyNTQ2ODkzMzc4NTYyMTEwNjQ3NjE5NTc2NyIsICJ2IjogIjYyNjQzMTU3NTQ5NjIwODkzNjI2OTE2Nzc5MTA4NzU3Njg3MTQ3MTk2MjgwOTcxNzM4MzQ4MjY5NDI2Mzk0NTYxNjI4NjEyNjQ3ODAyMDk2Nzk2MzI0NzYzMzgxMDQ3Mjg2NDg2NzQ2NjYwOTUyODI5MTA3MTczMTU2Mjg5NjYxNzQxMTE1MTYzMjQ3MzM2MTc2MDQ4ODM5Mjc5MzYwMzE4MzQxMzQ5NDQ1NjIyNDUzNDgzNTY1OTU0NzU5NDk3NjAxNDA4MjAyMDUwMTc4NDM3NjUyMjUxNzY5NDcyNTI1MzQ4OTEzODUzNDAwMzc2NTQ1Mjc4MjU2MDQzNzMwMzE2NDE2NjU3NjIyMzIxMTk0NzAxOTkxNzIyMDM5MTUwNzE4NzkyNjAyNzQ5MjI0ODIzMDg0MTk0NzU5Mjc1ODc4OTgyNjA4NDQwNDUzNDAwMDU3NTk3MDk1MDk3MTkyMzAyMjQ5MTc1NzcwODE0MzQ0OTg1MDU5OTk1MTkyNDY5OTQ0MzEwMTk4MDg2NDM3MTc0NTU1MjUwMjAyMzg4NTg5MDAwNzc5NTA4MDI0OTM0MjY2NjMyOTgyMTE3ODM4MjAwMTY4MzAwMTg0NDUwMzQyNjc5MjA0MjgxNDcyMTkzMjEyMDA0OTgxMjE4NDQ0NzE5ODYxNTYzOTM3MTAwNDE1MzIzNDc4OTAxNTU3NzM5MzM0NDA5Njc0ODUyOTI1MDk2NjkwOTI5OTA0MjA1MTMwNjI0MzA2NTk2Mzc2NDE3NjQxNjY1NTg1MTE1NzU4NjI2MDAwNzEzNjg0MzkxMzYzNDMxODAzOTQ0OTkzMTM0NjY2OTI0NjQ5MjMzODUzOTIzNzUzMzQ1MTE3Mjc3NjE4NzYzNjg2OTE1Njg1ODA1NzQ3MTYwMTE3NDcwMDg0NTYwMjcwOTI2NjMxODA2NjE3NDkwMjcyMjMxMjk0NTQ1Njc3MTU0NTY4NzYyNTgyMjU5NDU5OTgyNDEwMDc3NTE0NjI2MTg3Njc5MDc0OTkwNDQ3MTY5MTkxMTU2NTUwMjk5Nzk0Njc4NDUxNjI4NjMyMDQzMzkwMDI2MzI1MjMwODM4MTkiLCAic2UiOiAiMTYzODAzNzg4MTk3NjYzODQ2ODcyOTk4MDA5NjQzOTUxMDQzNDc0MjYxMzI0MTU2MDA2NzAwNzM0OTk1MDI5ODg0MDM1NzEwMzk1NTI0MjY5ODk0NDA3MzA1NjI0Mzk4NzI3OTkzODkzNTkzMjAyMTY2MjI0MzAxMjIxNDk2MzU4OTA2NTAyODAwNzM5MTk2MTY5NzAzMDg4NzU3MTM2MTE3Njk2MDI4MDU5MDczMTU3OTYxMDA4ODgwNTE1MTMxOTE3OTA5OTA3MjMxMTUxNTMwMTUxNzkyMzgyMTUyMDEwMTQ4NTg2OTcwMjA0NzYzMDExOTA4ODkyOTI3MzkxNDI2NDYwOTg2MTMzMzU2ODc2OTY2Nzg0NzQ0OTk2MTAwMzU4MjkwNDkwOTc1NTI3MDM5NzAzODcyMTY4NzIzNzQ4NDk3MzQ3MDg3NjQ2MDMzNzY5MTE2MDgzOTI4MTYwNjc1MDk1MDUxNzM1MTMzNzk5MDA1NDk5NTgwMDIyODc5NzU0MjQ2Mzc3NDQyNTg5ODI1MDgyMjcyMTA4MjE0NDU1NDUwNjMyODA1ODkxODM5MTQ1NjkzMzM4NzA2MzI5Njg1OTU2NTk3OTY3NDQwODgyODkxNjc3NzE2MzU2NDQxMDI5MjA4MjU3NDk5OTQyMDAyMTkxODYxMTA1MzI2NjIzNDgzMTE5NTkyNDc1NjUwNjY0MDYwMzAzMDk5NDU5OTg1MDEyODIyNDQ5ODYzMjMzMzY0MTA2Mjg3MjA2OTE1Nzc3MjAzMDgyNDIwMzIyNzk4ODgwMjQyNTAxNzk0MDkyMjIyNjE4MzkiLCAiYyI6ICI1NDY4NzA3MTg5NTE4MzkyNDA1NTQ0MjI2OTE0NDQ4OTc4NjkwMzE4NjQ1OTYzMTg3Nzc5MjI5NDYyNzg3OTEzNjc0NzgzNjQxMzUyMyJ9 -``` - -**Using proposed algorithm:** -``` -// Length: 1347 -AAAgf9w5lZgz95dY38QeT0XWJfaGrY-CSr8uDo82jptOTmUBAQChFsSOFc2fDgVDKCSs2KydOLvZbNLFXyB2qlJGTadW1ZBcZ2WvocXcKufEWrbDbTr58ySW_Om1HUmVy-ojBvh4fwAf6XETclSPE8MfctSE09pwpy4ZYpOabSdY2G6mt4U4j5YdCiuCEBnmiG7JaxgdHqW4cG3kSxX1JXmy2rE8S0uHFxqT3H4d2otX0Om9r9e6btmeA0mv4fqfy9gd9y7cxAE4Xw7nQp5y29yhA93gpHmfV0FNcEzvgmFBGhF5DzMEYGM7Bmoxip3zmlXDpn4Z3Q-SQWKuO1SEa-YPEjc7OkQN8GjEweQAP6zUNoDD7FQtGdhXsJ0gq9tLz_Xw_x3BAgBLEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVC4ox7flXlg7AEkAhB-3AwFVCeRcF6Ii4FMqDfJ04FB_vm7NdqoWcfHARRmFzgUgMYoiB04kz5CDzzIVuowqkIbRgrlC7CKryuzuqNiCF3mfQkvJWfK3qXFNBKp2ZBVxYUo92l0LbE0cBAG3p_ZB26PO5XSS8Nw8U7uWJPkG0rQxreZcgEtw1WFNEzfpiTLN-W4xGneTYqot3VDFMXjmn0i37nPhdSSvfnSkk6PDJWi8H5Op-Zm03f5o6cWTW-vyL0p8x0dcvYGLPxDSLnbeP0Fc95KewHAtfWSn4gdQ7C2fzc8pZ9UV9iUIIDtdhDV306h-ZUhO641o2BTIa3fDQi7X590gIdhYhAUfIarHGzvXdff6OatwALnJqhAY2jbGopyrpgsTb9i7SOYwkztTJbHQ139Syv75uJ1rrGDzm_feXNGvM-ta8sr4sdD51vcOhVlFeDPD3R8iEqNbOGuj6-wJlmyF8CsEAQCBwfG7CL3X9rS6GkDsCmkw18__K8cSaePD4YWFDQHBqnzu6nOIy6RGa8U6tXgJbqZPGcBg9Db6W0iwkub9N36nadgqjPQkhuxt0U8H-p6NkPfbqqjZ3dDqNmDAuvr96_MItOSdPI_kRhyhJK9779Lg6iWyakimJ1QViqsefO-1uE-MQ0FXqs4ZcC-V187LXc2IHpJwk2d8Oo66oQij__Gcn4h0qQf0rC8TNy54_IQTSns080AK7Yfy12nMWBnWJN_7d4CToSpDAehyn2YEBPmweGuVnXu-DEjAbeEGFbsTYsCHygo_yzBpndRguYruDzn2yyt3RkyWISFYRZzEL1xPBQAgeOfJKl30pg6m-np2OmrRYp8Z_x3FqdwRHoWruiF0FlM -``` - -##### Encoding steps - -1. Iterate over object `attributes` -2. Get **size** (`number bytes`) required for each attribute value (`BigNumber`) and **value as bytes** (big-endian) -3. Append `number bytes` (reserve 2 bytes for it) and `value as bytes` to resulting array -4. After adding all attributes encode the resulting bytes array as base64 string - -**Value encoding rules:** -* BigNumber: get value size and bytes -* Nested object: apply the same steps to encode itself as bytes -* Array: get count of elements and encode each element -* Optional values: use zero as size and empty array for value -* Map: encode key and value as usual - -##### Decoding steps - -1. Read 2 bytes corresponding to the attribute value size -2. Read next N bytes corresponding to the value size -3. Restore value from bytes -4. Repeat the process for the tail - -#### Credential Signature encoding - -Fields order: -* `Signature: `[signature, signature_correctness_proof] -* `CredentialSignature: `[a, e, m_2, v]` -* `SignatureCorrectnessProof: `[c, se]` - -```rust -/// Need to construct an object containing CredentialSignature and SignatureCorrectnessProof -struct Signature { - signature: CredentialSignature, - signature_correctness_proof: SignatureCorrectnessProof, -} - -/// Encoding fields order: [signature, signature_correctness_proof] -impl Signature { - fn to_bytes(&self) -> Vec { - let (signature_size, signature_bytes) = self.signature.get_size_and_bytes(); - let (signature_correctness_proof_size, signature_correctness_proof_bytes) = self.signature_correctness_proof.get_size_and_bytes(); - vec![ - ..signature_size, - ..signature_bytes, - ..signature_correctness_proof_size, - ..signature_correctness_proof_bytes, - ] - } - - fn from_bytes(bytes: &[u8]) -> SignatureCorrectnessProof { - // set start and end - let signature: CredentialSignature = CredentialSignature::from_bytes(&bytes[start..end]); - // change start and end - let signature_correctness_proof: SignatureCorrectnessProof = SignatureCorrectnessProof::from_bytes(&bytes[start..end]); - Signature { - signature, - signature_correctness_proof, - } - } -} - -/// Similar implementation for `CredentialSignature` and `SignatureCorrectnessProof` objects -``` - -#### Presentation Proof encoding - -Fields coder: -* `SubProof: `[non_revoc_proof, primary_proof] -* `PrimaryProof: `[eq_proof, ge_proofs]` - * because `ge_proofs` is an array we need to append elements count into the resulting array -* `NonRevocProof: `[c_list, x_list]` - -```rust -/// Need to construct an object containing CredentialSignature and SignatureCorrectnessProof -struct SubProof { - primary_proof: PrimaryProof, - non_revoc_proof: Option, -} - -/// Encoding fields order: [non_revoc_proof, primary_proof] -impl SubProof { - fn to_bytes(&self) -> Vec { - // use `0` for `non_revoc_proof_size` and empty array for `non_revoc_proof_bytes` (all Optional fields) - let (non_revoc_proof_size, non_revoc_proof_bytes) = self.non_revoc_proof.get_size_and_bytes(); - let (primary_proof_size, non_revoc_proof_bytes) = self.non_revoc_proof.get_size_and_bytes(); - vec![ - ..non_revoc_proof_size, - ..non_revoc_proof_bytes, - ..primary_proof_size, - ..non_revoc_proof_bytes, - ] - } - - fn from_bytes(bytes: &[u8]) -> SignatureCorrectnessProof { - // set start and end - let non_revoc_proof: NonRevocProof = NonRevocProof::from_bytes(&bytes[start..end]); - // change start and end - let primary_proof: PrimaryProof = PrimaryProof::from_bytes(&bytes[start..end]); - SubProof { - non_revoc_proof, - primary_proof, - } - } -} -``` \ No newline at end of file diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 943c8888..1bd9c296 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -60,7 +60,6 @@ verifiable credential and presentation described in the [document](). * Basic approach used in Aries attachments: [BaseURL safe 64 encoding of object serialized as JSON string](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url)? * Compact encoding implemented in Python PoC: Using the fact that most fields of credential signature and proof are big numbers rather that strings. * For example: the length of encoded credential signature string is about 2.5 times less than in the basic approach - * Find an [example data](./encoding.md#example) to see the difference * **Answer**: * Start from basic Aries encoding. * Experiment with other algorithms (CBOR, Message Pack, Protobuf, Custom) as a next step. From d7acffc5c58e41c94497dfda19f6b2794e0a045b Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Wed, 6 Dec 2023 17:35:05 +0300 Subject: [PATCH 12/13] Updated version of `anoncreds-clsignatures` crate and fix documentation for updating revocation state Signed-off-by: artem.ivanov --- Cargo.toml | 2 +- docs/design/w3c/w3c-representation.md | 11 +++-------- src/services/prover.rs | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b78508bb..b458d800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ logger = ["dep:env_logger"] vendored = ["anoncreds-clsignatures/openssl_vendored"] [dependencies] -anoncreds-clsignatures = "0.2.2" +anoncreds-clsignatures = "0.2.4" bs58 = "0.4.0" env_logger = { version = "0.9.3", optional = true } ffi-support = { version = "0.4.0", optional = true } diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 1bd9c296..01480543 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -402,7 +402,6 @@ pub extern "C" fn anoncreds_create_w3c_credential_request( /// cred_request: object handle pointing to the credential request /// attr_names: list of attribute names /// attr_raw_values: list of attribute raw values -/// encoding: encoding algorithm to apply for attribute values /// revocation: object handle pointing to the credential revocation info /// cred_p: reference that will contain credential (in W3C form) instance pointer /// @@ -416,7 +415,6 @@ pub extern "C" fn anoncreds_create_w3c_credential( cred_request: ObjectHandle, attr_names: FfiStrList, attr_raw_values: FfiStrList, - encoding: FfiStr, revocation: *const FfiCredRevInfo, cred_p: *mut ObjectHandle, ) -> ErrorCode {} @@ -674,8 +672,7 @@ extartnal_verifier.verify_rsa_integrity_proof_presentation(rsa_integrity_proof_p "credentialSchema": { "type": "AnonCredsDefinition", "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", - "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", - "encoding": "auto" + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0" }, "credentialSubject": { "first_name": "Alice" @@ -803,8 +800,7 @@ Example of an AnonCreds W3C credential: "credentialSchema": { "type": "AnonCredsDefinition", "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", - "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", - "encoding": "auto" + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0" }, "credentialSubject": { "firstName": "Alice", @@ -852,8 +848,7 @@ Example of an AnonCreds W3C presentation: "credentialSchema": { "type": "AnonCredsDefinition", "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", - "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0", - "encoding": "auto" + "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0" }, "credentialSubject":{ "firstName":"Alice", diff --git a/src/services/prover.rs b/src/services/prover.rs index 53b7ac2b..af5ca4ba 100644 --- a/src/services/prover.rs +++ b/src/services/prover.rs @@ -625,7 +625,7 @@ pub fn create_revocation_state_with_witness( /// prover::create_or_update_revocation_state(&rev_reg_def.value.tails_location, /// &rev_reg_def, /// &rev_status_list, -/// 0, +/// 1, /// None, /// None /// ).expect("Unable to create or update the revocation state"); From dbdf927806ad793742defaf957758efe8abe2c7e Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Wed, 6 Dec 2023 17:56:32 +0300 Subject: [PATCH 13/13] Removed questions section and clean up Signed-off-by: artem.ivanov --- docs/design/w3c/w3c-representation.md | 233 ++++---------------------- 1 file changed, 34 insertions(+), 199 deletions(-) diff --git a/docs/design/w3c/w3c-representation.md b/docs/design/w3c/w3c-representation.md index 01480543..1d140b0b 100644 --- a/docs/design/w3c/w3c-representation.md +++ b/docs/design/w3c/w3c-representation.md @@ -1,10 +1,6 @@ ## Design for W3C representation of AnonCreds credentials and presentation -Currently `anoncreds-rs` library only provides support for legacy 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 describes how W3C formatted Verifiable Credentials and Presentations are supported in `anoncreds-rs` library. ### Goals and ideas @@ -31,119 +27,6 @@ verifiable credential and presentation described in the [document](). * Presentations: Verify validity of presentations including non-AnonCreds 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? - * **Answer**: No conversion for Credential Offer, Credential Request objects. Existing types will be used. -* 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. - * **Answer:** - * All methods will be duplicated - * According to the Q1 answer `w3c_create_offer`, `w3c_create_request` methods will be returning the same object as original methods -* Q3: Are we still tied to legacy 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. - * **Answer**: API methods will keep using an existing AnonCreds Presentation Request format -* Q4: Do we want to provide general interfaces doing signing and verification of Non-AnonCreds 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 - * **Answer:** No. - * Third party libraries must be used for doing signing and verification of Non-AnonCreds Data Integrity proof signature - * AnonCreds-rs only will only provide helper methods for setting attributes which can be needed for different Non-AnonCreds Data Integrity proof -* Q5: Signature/Proof encoding: Which approach to use for encoding? - * Basic approach used in Aries attachments: [BaseURL safe 64 encoding of object serialized as JSON string](https://github.com/hyperledger/aries-rfcs/tree/main/concepts/0017-attachments#base64url)? - * Compact encoding implemented in Python PoC: Using the fact that most fields of credential signature and proof are big numbers rather that strings. - * For example: the length of encoded credential signature string is about 2.5 times less than in the basic approach - * **Answer**: - * Start from basic Aries encoding. - * Experiment with other algorithms (CBOR, Message Pack, Protobuf, Custom) as a next step. -* Q6: W3C data model allows attributes to be represented not only as key/value string pairs but also as - objects and arrays. - * If we want to support more complex representations for the W3C AnonCreds credential attributes and their - presentations, we need to design following things: - * how encoding will work for such attributes - * how selective disclosure will work on top level attribute itself - ``` - "credentialSubject": { - "address": { - "type": "Address", - "city": "Foo", - "street": "Main str." - } - } - ``` - * **Answer**: - * Only key/value string pairs will be supported for the current phase -* Q7: Should we care about back way conversion of credential issued in W3C form? - * Assume that we issued W3C which cannot convert back into legacy 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 - * **Answer**: Yes. Within the current design/effort credentials must be convertible back and forth -* Q8: Should we include Holder DID into credential subject as [`id` attribute](https://www.w3.org/TR/vc-data-model/#identifiers)? - * This enables credential subject [validation](https://www.w3.org/TR/vc-data-model/#credential-subject-0) - * We can add if for newly issued credentials but cannot set during the conversion of previously issued credentials. - * **Answer**: - * Up to Issuer, Optionally Issuer may include DID into credential subject - * anoncreds-rs will provide a helper function to set `id` -* Q9: 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" - } - ... - } - ``` - * **Answer**: Need more discussion -* Q10: Should we remove `mapping` completely or move under encoded `proofValue`? - * Why `mapping` is bad: we make presentation tied to legacy styled Presentation Request - * Mapping is something old-fashioned synthetic required for doing validation (not signature verification) that proof matches to - the request itself on the verifier side - * For doing crypto `proofValue` verification we only need the names of revealed attributes and predicated (with - type) - * `revealed attributes` and `predicates` can be validated as we include them into `credentialSubject` but `unrevealed` attributes cannot. - * **Answer**: Drop `mapping` - see at the bottom of the document an example on how the validation of verifier's side still can be done -* Q11: Revocation signature/proof: Should it be put into the same value of two independent signatures/proofs must be put into credential/presentation? - * **Answer**: For the current implementation it's good just to put everything inside encoded proof value - * For future: Prepare a section example describing how non revocation can be extracted into a separate proof -* Q12: For conversion of legacy credentials into W3C Credentials form we need to set `issuer_id` attribute. But legacy - credentials do not contain this field explicitly. `AnonCreds-rs` is designed to be ledger/DID method agnostic, so it - does not analyze/handle the values of id fields. - * How should we get issuer DID for putting into credential? - * Require `CredentialDefinition` to be passed as parameter - * Parse if `legacy` cred def id form is used - * **Answer**: Require passing credential definition as parameter -* Q13: Issuance data: W3C specification requires setting of `issuanceDate` property to express the date and time when a credential becomes valid. - * What datetime should we use? current / random of the day / start of the day - * **Answer**: It's ok just to use the current time - -### Proposed implementation path for first iteration - -1. Credential conversion APIs -2. Credential helper methods for non-AnonCreds integrity proof handling (set_integrity_proof, etc?) - * Generation and verification of non-AnonCreds 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: All methods -4. No adoption of Credential Offer and Credential Request objects for W3C standard -5. Keep API stick to existing Presentation Request format - ### Public API #### Credential/Presentation Conversion methods @@ -165,6 +48,7 @@ Methods purpose - have to forms of credentials (probably even duplicate in walle /// /// # Params /// cred: object handle pointing to credential in legacy form to convert +/// cred_def: object handle pointing to the credential definition /// cred_p: reference that will contain converted credential (in W3C form) instance pointer /// /// # Returns @@ -172,6 +56,7 @@ Methods purpose - have to forms of credentials (probably even duplicate in walle #[no_mangle] pub extern "C" fn anoncreds_credential_to_w3c( cred: ObjectHandle, + cred_def: ObjectHandle, cred_p: *mut ObjectHandle, ) -> ErrorCode {} @@ -267,67 +152,23 @@ pub extern "C" fn anoncreds_w3c_credential_set_subject_id( /// # Returns /// Error code #[no_mangle] -pub extern "C" fn anoncreds_w3c_credential_id( +pub extern "C" fn anoncreds_w3c_credential_set_id( cred: ObjectHandle, id: FfiStr, cred_p: *mut ObjectHandle, ) -> 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 legacy formatted presentation and APIs to convert it into/from -W3C form to support different Verifiers. - -```rust -/// Convert legacy styled AnonCreds presentation into W3C AnonCreds presentation form -/// The conversion process described at the specification: --- -/// -/// # Params -/// cred - object handle pointing to legacy styled AnonCreds presentation to convert -/// cred_p - reference that will contain converted presentation (in W3C form) instance pointer -/// -/// # Returns -/// Error code -#[no_mangle] -pub extern "C" fn anoncreds_presentation_to_w3c( - cred: ObjectHandle, - cred_p: *mut ObjectHandle, -) -> ErrorCode {} - -/// Convert W3C styled AnonCreds presentation into legacy styled AnonCreds presentation -/// The conversion process described at the specification: --- -/// -/// # Params -/// cred - object handle pointing to W3C styled AnonCreds presentation to convert -/// cred_p - reference that will contain converted presentation (in legacy form) instance pointer -/// -/// # Returns -/// Error code -#[no_mangle] -pub extern "C" fn anoncreds_presentation_from_w3c( - cred: ObjectHandle, - cred_p: *mut ObjectHandle, -) -> ErrorCode {} -``` - -#### Optional: Methods duplication +#### Flow methods duplication 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. -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 @@ -344,8 +185,6 @@ The reasons for adding duplication methods: - presentation conversion methods are not needed anymore in this case - 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 - ```rust /// Create Credential Offer according to the AnonCreds specification /// Note that Credential Offer still will be legacy styled (the same as result of anoncreds_create_credential_offer) @@ -444,7 +283,7 @@ pub extern "C" fn anoncreds_process_w3c_credential( /// Get value of requested credential attribute as string /// /// # Params -/// cred_def: object handle pointing to the credential (in W3 form) +/// handle: object handle pointing to the credential (in W3 form) /// name: name of attribute to retrieve /// result_p: reference that will contain value of request credential attribute /// @@ -789,14 +628,14 @@ Example of an AnonCreds W3C credential: { "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://raw.githubusercontent.com/DSRCorporation/anoncreds-rs/design/w3c-support/docs/design/w3c/context.json" + "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json" ], "type": [ "VerifiableCredential", "AnonCredsCredential" ], "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", - "issuanceDate": "2023-10-26T01:17:32Z", + "issuanceDate": "2023-11-15T10:00:00.036203Z", "credentialSchema": { "type": "AnonCredsDefinition", "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", @@ -809,7 +648,7 @@ Example of an AnonCreds W3C credential: }, "proof": [ { - "type": "CLSignature2023", + "type": "AnonCredsProof2023", "signature": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM" }, { @@ -827,21 +666,21 @@ Example of an AnonCreds W3C presentation: ```json { - "@context":[ + "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://raw.githubusercontent.com/DSRCorporation/anoncreds-spec/w3c-credentials/data/anoncreds-w3c-context.json" + "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json" ], - "type":[ + "type": [ "VerifiablePresentation", "AnonCredsPresentation" ], - "verifiableCredential":[ + "verifiableCredential": [ { - "@context":[ + "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://raw.githubusercontent.com/DSRCorporation/anoncreds-spec/w3c-credentials/data/anoncreds-w3c-context.json" + "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json" ], - "type":[ + "type": [ "VerifiableCredential", "AnonCredsCredential" ], @@ -850,32 +689,28 @@ Example of an AnonCreds W3C presentation: "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default", "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0" }, - "credentialSubject":{ - "firstName":"Alice", - "age":{ - "type":"AnonCredsPredicate", - "p_type":">=", - "p_value":18 - } + "credentialSubject": { + "firstName": "Alice", + "age": [ + { + "type": "AnonCredsPredicate", + "predicate": ">=", + "value": 18 + } + ] }, - "issuanceDate":"2023-11-15T10:59:48.036203Z", - "issuer":"issuer:id/path=bar", - "proof":{ - "type":"AnonCredsPresentationProof2023", - "mapping":{ - "predicates":["predicate1_referent"], - "revealedAttributeGroups":[], - "revealedAttributes":["attr1_referent"], - "unrevealedAttributes":[] - }, - "proofValue":"eyJzdWJfcHJvb2Yi...zMTc1NzU0NDAzNDQ0ODUifX1dfX19" + "issuanceDate": "2023-11-15T10:59:48.036203Z", + "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W", + "proof": { + "type": "AnonCredsPresentationProof2023", + "proofValue": "eyJzdWJfcHJvb2Yi...zMTc1NzU0NDAzNDQ0ODUifX1dfX19" } } ], - "proof":{ - "type":"AnonCredsPresentationProof2023", - "challenge":"413296376279822794586260", - "proofValue":"eyJhZ2dyZWdhdGVkIjp7ImNfaGFzaCI6IjEwMT...IsMzAsMTM1LDE4MywxMDcsMTYwXV19fQ==" + "proof": { + "type": "AnonCredsPresentationProof2023", + "challenge": "413296376279822794586260", + "proofValue": "eyJhZ2dyZWdhdGVkIjp7ImNfaGFzaCI6IjEwMT...IsMzAsMTM1LDE4MywxMDcsMTYwXV19fQ==" } } ``` \ No newline at end of file