Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ZKP verification #792

Merged
merged 12 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ lazy val D = new {
"com.github.dasniko" % "testcontainers-keycloak" % V.testContainersJavaKeycloak % Test

val doobiePostgres: ModuleID = "org.tpolecat" %% "doobie-postgres" % V.doobie
val doobiePostgresCirce: ModuleID = "org.tpolecat" %% "doobie-postgres-circe" % V.doobie
val doobieHikari: ModuleID = "org.tpolecat" %% "doobie-hikari" % V.doobie
val flyway: ModuleID = "org.flywaydb" % "flyway-core" % V.flyway

Expand All @@ -157,7 +158,7 @@ lazy val D = new {

// LIST of Dependencies
val doobieDependencies: Seq[ModuleID] =
Seq(doobiePostgres, doobieHikari, flyway)
Seq(doobiePostgres, doobiePostgresCirce, doobieHikari, flyway)
}

lazy val D_Shared = new {
Expand Down
110 changes: 108 additions & 2 deletions docs/docusaurus/credentials/present-proof.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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.

<Tabs groupId="vc-formats">
<TabItem value="jwt" label="JWT">

```bash
curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \
-H 'accept: application/json' \
Expand All @@ -72,6 +78,56 @@ curl -X 'POST' 'http://localhost:8070/prism-agent/present-proof/presentations' \
}'
```

</TabItem>
<TabItem value="anoncreds" label="AnonCreds">

```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"
}'
```
</TabItem>
</Tabs>

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:
Expand Down Expand Up @@ -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:

<Tabs groupId="vc-formats">
<TabItem value="jwt" label="JWT">

```bash
curl -X 'PATCH' 'http://localhost:8090/prism-agent/present-proof/presentations/{PRESENTATION_ID}' \
-H 'Content-Type: application/json' \
Expand All @@ -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.

</TabItem>
<TabItem value="anoncreds" label="AnonCreds">

```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"
]
}
]
}
}'
```
</TabItem>
</Tabs>

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
Expand All @@ -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)
### JWT Present Proof Flow Diagram
![](present-proof-flow.png)
### Anoncreds Present Proof Flow Diagram
![](anoncreds-present-proof-flow.png)

<Tabs groupId="vc-formats">
<TabItem value="jwt" label="JWT">

![](present-proof-flow.png)

</TabItem>
<TabItem value="anoncreds" label="AnonCreds">

![](anoncreds-present-proof-flow.png)

</TabItem>
</Tabs>
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ object AnoncredLib {
version: String, // SCHEMA_Version
attr_names: AttributeNames,
issuer_id: IssuerId, // ISSUER_DID
): SchemaDef = uniffi.anoncreds_wrapper.Schema.apply(name, version, attr_names.toSeq.asJava, issuer_id)
): AnoncredSchemaDef = uniffi.anoncreds_wrapper.Schema.apply(name, version, attr_names.toSeq.asJava, issuer_id)

// issuer
def createCredDefinition(
issuer_id: String,
schema: SchemaDef,
schema: AnoncredSchemaDef,
tag: String,
supportRevocation: Boolean,
signature_type: uniffi.anoncreds_wrapper.SignatureType.CL.type = uniffi.anoncreds_wrapper.SignatureType.CL
) = {
): AnoncredCreateCredentialDefinition = {
val credentialDefinition: uniffi.anoncreds_wrapper.IssuerCreateCredentialDefinitionReturn =
uniffi.anoncreds_wrapper
.Issuer()
Expand All @@ -40,7 +40,7 @@ object AnoncredLib {
uniffi.anoncreds_wrapper.CredentialDefinitionConfig(supportRevocation)
)

CreateCredentialDefinition(
AnoncredCreateCredentialDefinition(
credentialDefinition.getCredentialDefinition(),
credentialDefinition.getCredentialDefinitionPrivate(),
credentialDefinition.getCredentialKeyCorrectnessProof()
Expand All @@ -49,9 +49,9 @@ object AnoncredLib {

// issuer
def createOffer(
credentialDefinition: CreateCredentialDefinition,
credentialDefinition: AnoncredCreateCredentialDefinition,
credentialDefinitionId: String
): CredentialOffer =
): AnoncredCredentialOffer =
uniffi.anoncreds_wrapper
.Issuer()
.createCredentialOffer(
Expand All @@ -62,15 +62,15 @@ object AnoncredLib {

// holder
def createCredentialRequest(
linkSecret: LinkSecretWithId,
credentialDefinition: CredentialDefinition,
credentialOffer: CredentialOffer,
linkSecret: AnoncredLinkSecretWithId,
credentialDefinition: AnoncredCredentialDefinition,
credentialOffer: AnoncredCredentialOffer,
entropy: String = {
val tmp = scala.util.Random()
tmp.setSeed(java.security.SecureRandom.getInstanceStrong().nextLong())
tmp.nextString(80)
}
): CreateCrendentialRequest = {
): AnoncredCreateCrendentialRequest = {
val credentialRequest =
uniffi.anoncreds_wrapper
.Prover()
Expand All @@ -83,16 +83,16 @@ object AnoncredLib {
credentialOffer, // CredentialOffer credential_offer
)

CreateCrendentialRequest(credentialRequest.getRequest(), credentialRequest.getMetadata())
AnoncredCreateCrendentialRequest(credentialRequest.getRequest(), credentialRequest.getMetadata())
yshyn-iohk marked this conversation as resolved.
Show resolved Hide resolved
}

// holder
def processCredential(
credential: Credential,
metadata: CredentialRequestMetadata,
linkSecret: LinkSecretWithId,
credentialDefinition: CredentialDefinition,
): Credential = {
credential: AnoncredCredential,
metadata: AnoncredCredentialRequestMetadata,
linkSecret: AnoncredLinkSecretWithId,
credentialDefinition: AnoncredCredentialDefinition,
): AnoncredCredential = {
uniffi.anoncreds_wrapper
.Prover()
.processCredential(
Expand All @@ -106,16 +106,16 @@ object AnoncredLib {

// issuer
def createCredential(
credentialDefinition: CredentialDefinition,
credentialDefinitionPrivate: CredentialDefinitionPrivate,
credentialOffer: CredentialOffer,
credentialRequest: CredentialRequest,
credentialDefinition: AnoncredCredentialDefinition,
credentialDefinitionPrivate: AnoncredCredentialDefinitionPrivate,
credentialOffer: AnoncredCredentialOffer,
credentialRequest: AnoncredCredentialRequest,
attributeValues: Seq[(String, String)]
// java.util.List[AttributeValues] : java.util.List[AttributeValues]
// revocationRegistryId : String
// revocationStatusList : RevocationStatusList
// credentialRevocationConfig : CredentialRevocationConfig
): Credential = {
): AnoncredCredential = {
uniffi.anoncreds_wrapper
.Issuer()
.createCredential(
Expand All @@ -140,13 +140,13 @@ object AnoncredLib {
// [info] Caused by: Predicate is not satisfied

def createPresentation(
presentationRequest: PresentationRequest,
credentialRequests: Seq[CredentialAndRequestedAttributesPredicates],
presentationRequest: AnoncredPresentationRequest,
credentialRequests: Seq[AnoncredCredentialRequests],
selfAttested: Map[String, String],
linkSecret: LinkSecret,
schemas: Map[SchemaId, SchemaDef],
credentialDefinitions: Map[CredentialDefinitionId, CredentialDefinition],
): Either[uniffi.anoncreds_wrapper.AnoncredsException.CreatePresentationException, Presentation] = {
linkSecret: AnoncredLinkSecret,
schemas: Map[SchemaId, AnoncredSchemaDef],
credentialDefinitions: Map[CredentialDefinitionId, AnoncredCredentialDefinition],
): Either[uniffi.anoncreds_wrapper.AnoncredsException.CreatePresentationException, AnoncredPresentation] = {
try {
Right(
uniffi.anoncreds_wrapper
Expand Down Expand Up @@ -181,10 +181,10 @@ object AnoncredLib {

// FIXME its always return false ....
def verifyPresentation(
presentation: Presentation,
presentationRequest: PresentationRequest,
schemas: Map[SchemaId, SchemaDef],
credentialDefinitions: Map[CredentialDefinitionId, CredentialDefinition],
presentation: AnoncredPresentation,
presentationRequest: AnoncredPresentationRequest,
schemas: Map[SchemaId, AnoncredSchemaDef],
credentialDefinitions: Map[CredentialDefinitionId, AnoncredCredentialDefinition],
): Boolean = {
uniffi.anoncreds_wrapper
.Verifier()
Expand Down
Loading
Loading