diff --git a/docs/docusaurus/credentials/present-proof.md b/docs/docusaurus/credentials/present-proof.md index 4509eac59b..9469c57af1 100644 --- a/docs/docusaurus/credentials/present-proof.md +++ b/docs/docusaurus/credentials/present-proof.md @@ -1,3 +1,6 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Present proof The [Present Proof Protocol](/docs/concepts/glossary#present-proof-protocol) allows: @@ -57,6 +60,9 @@ To do this, he makes a `POST` request to the [`/present-proof/presentations`](/a 1. `connectionId`: This field represents the unique identifier of an existing connection between the verifier and the Holder/prover. It is for exchanging messages related to the protocol flow execution. 2. `challenge` and `domain`: The Verifier provides the random seed challenge and operational domain, and the Holder/Prover must sign the generated proof to protect from replay attacks. + + + ```bash curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \ -H 'accept: application/json' \ @@ -72,6 +78,56 @@ curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \ }' ``` + + + +```bash +curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H "apikey: $API_KEY" \ + -d '{ + "connectionId": "872ddfa9-4115-46c2-8a1b-22c24c7431d7", + "anoncredPresentationRequest": { + "requested_attributes": { + "attribute1": { + "name": "Attribute 1", + "restrictions": [ + { + "cred_def_id": "credential_definition_id_of_attribute1" + } + ], + "non_revoked": { + "from": 1635734400, + "to": 1735734400 + } + } + }, + "requested_predicates": { + "predicate1": { + "name": "age", + "p_type": ">=", + "p_value": 18, + "restrictions": [ + { + "schema_id": "schema_id_of_predicate1" + } + ], + "non_revoked": { + "from": 1635734400 + } + } + }, + "name": "Example Presentation Request", + "nonce": "1234567890", + "version": "1.0" + }, + "credentialFormat": "AnonCreds" + }' +``` + + + Upon execution, a new presentation request record gets created with an initial state of `RequestPending`. The Verifier PRISM Agent will send the presentation request message to the PRISM Agent of the Holder/Prover through the specified DIDComm connection. The record state then is updated to `RequestSent`. The Verifier can retrieve the list of presentation records by making a `GET` request to the [`/present-proof/presentations`](/agent-api/#tag/Present-Proof/operation/getAllPresentation) endpoint: @@ -121,6 +177,9 @@ curl -X 'GET' 'http://localhost:8090/prism-agent/present-proof/presentations' \ The Holder/Prover can then accept a specific request, generate the proof, and send it to the Verifier PRISM Agent by making a `PATCH` request to the [`/present-proof/presentations/{id}`](/agent-api/#tag/Present-Proof/operation/updatePresentation) endpoint: + + + ```bash curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{PRESENTATION_ID}' \ -H 'Content-Type: application/json' \ @@ -133,8 +192,39 @@ curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{ The Holder/Prover will have to provide the following information: 1. `presentationId`: The unique identifier of the presentation record to accept. -2. `proofId`: The unique identifier of the verifiable credential record to use as proof. +2. `proofId`: The unique identifier of the verifiable credential record to use as proof. + + + + +```bash +curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{PRESENTATION_ID}' \ + -H 'Content-Type: application/json' \ + -H "apikey: $API_KEY" \ + -d '{ + "action": "request-accept", + "anoncredPresentationRequest":{ + "credentialProofs":[ + { + "credential":"3e849b98-f0fd-4cb4-ae96-9ea527a76267", + "requestedAttribute":[ + "age" + ], + "requestedPredicate":[ + "age" + ] + } + ] + } + }' +``` + + +The Holder/Prover will have to provide the following information: +1. `presentationId`: The unique identifier of the presentation record to accept. +2. `anoncredPresentationRequest`: A list of credential unique identifier with the attribute and predicate the credential is answering for. + The record state is updated to `PresentationPending` and processed by the Holder/Prover PRISM Agent. The agent will automatically generate the proof presentation, change the state to `PresentationGenerated`, and will eventually send it to the Verifier Agent, and change the state to `PresentationSent`. ```mermaid @@ -152,4 +242,20 @@ stateDiagram-v2 The following diagram shows the end-to-end flow for a verifier to request and verify a proof presentation from a Holder/prover. -![](present-proof-flow.png) \ No newline at end of file +### JWT Present Proof Flow Diagram +![](present-proof-flow.png) +### Anoncreds Present Proof Flow Diagram +![](anoncreds-present-proof-flow.png) + + + + +![](present-proof-flow.png) + + + + +![](anoncreds-present-proof-flow.png) + + + \ No newline at end of file diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationAction.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationAction.scala index 08488ddca4..114b08893a 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationAction.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationAction.scala @@ -20,18 +20,6 @@ final case class RequestPresentationAction( anoncredPresentationRequest: Option[AnoncredCredentialProofsV1], ) -final case class AnoncredProof( - @description(annotations.credential.description) - @encodedExample(annotations.credential.example) - credential: String, - @description(annotations.requestedAttribute.description) - @encodedExample(annotations.requestedAttribute.example) - requestedAttribute: Seq[String], - @description(annotations.requestedPredicate.description) - @encodedExample(annotations.requestedPredicate.example) - requestedPredicate: Seq[String] -) - object RequestPresentationAction { object annotations { object action @@ -55,7 +43,7 @@ object RequestPresentationAction { ) object anoncredProof - extends Annotation[Option[Seq[AnoncredProof]]]( + extends Annotation[Option[AnoncredCredentialProofsV1]]( description = "A list of proofs from the Anoncred library, each corresponding to a credential.", example = None ) @@ -66,18 +54,6 @@ object RequestPresentationAction { "The unique identifier of the issue credential record - and hence VC - to use as the prover accepts the presentation request. Only applicable on the prover side when the action is `request-accept`.", example = "id" ) - - object requestedAttribute - extends Annotation[Seq[String]]( - description = "The unique identifier of attribute that the credential is expected to provide.", - example = Seq("Attribute1", "Attribute2") - ) - - object requestedPredicate - extends Annotation[Seq[String]]( - description = "The unique identifier of Predicate that the credential is expected to answer for.", - example = Seq("Predicate1", "Predicate2") - ) } given RequestPresentationActionEncoder: JsonEncoder[RequestPresentationAction] = @@ -86,16 +62,8 @@ object RequestPresentationAction { given RequestPresentationActionDecoder: JsonDecoder[RequestPresentationAction] = DeriveJsonDecoder.gen[RequestPresentationAction] - given AnoncredProofEncoder: JsonEncoder[AnoncredProof] = - DeriveJsonEncoder.gen[AnoncredProof] - - given AnoncredProofDecoder: JsonDecoder[AnoncredProof] = - DeriveJsonDecoder.gen[AnoncredProof] - given RequestPresentationActionSchema: Schema[RequestPresentationAction] = Schema.derived - given AnoncredProofSchema: Schema[AnoncredProof] = Schema.derived - import AnoncredCredentialProofsV1.given given Schema[AnoncredCredentialProofsV1] = Schema.derived diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationInput.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationInput.scala index dd460c4c25..9f3c677fa8 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationInput.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/presentproof/controller/http/RequestPresentationInput.scala @@ -19,8 +19,8 @@ final case class RequestPresentationInput( @description(annotations.proofs.description) @encodedExample(annotations.proofs.example) proofs: Seq[ProofRequestAux], - @description(annotations.proofs.description) // TODO - @encodedExample(annotations.proofs.example) // TODO + @description(annotations.anoncredPresentationRequest.description) + @encodedExample(annotations.anoncredPresentationRequest.example) anoncredPresentationRequest: Option[AnoncredPresentationRequestV1], @description(annotations.credentialFormat.description) @encodedExample(annotations.credentialFormat.example) @@ -46,6 +46,54 @@ object RequestPresentationInput { example = Seq.empty ) + object anoncredPresentationRequest + extends Annotation[Option[AnoncredPresentationRequestV1]]( + description = "Anoncred Presentation Request", + example = Some( + AnoncredPresentationRequestV1( + requested_attributes = Map( + "attribute1" -> AnoncredRequestedAttributeV1( + "Attribute 1", + List( + Map( + "cred_def_id" -> "credential_definition_id_of_attribute1" + ) + ), + Some( + AnoncredNonRevokedIntervalV1( + Some(1635734400), + Some(1735734400) + ) + ) + ) + ), + requested_predicates = Map( + "predicate1" -> + AnoncredRequestedPredicateV1( + "Predicate 1", + ">=", + 18, + List( + Map( + "schema_id" -> "schema_id_of_predicate1" + ) + ), + Some( + AnoncredNonRevokedIntervalV1( + Some(1635734400), + None + ) + ) + ) + ), + name = "Example Presentation Request", + nonce = "1234567890", + version = "1.0", + non_revoked = None + ) + ) + ) + object credentialFormat extends Annotation[Option[String]]( description = "The credential format (default to 'JWT')",