From 4d70d93cc90127ba2f0217a40578192dcac3a5a2 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Thu, 2 Nov 2023 17:28:38 +0300 Subject: [PATCH] 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 | 382 +++++++++++++++++++ 4 files changed, 1109 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..5223be7f --- /dev/null +++ b/docs/design/w3c/w3c-representation.md @@ -0,0 +1,382 @@ +## 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 as the last extra step. + +#### 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 need if we decide not to implement duplication flow methods. +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 w3c presentation. + +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 + +```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.