pierg / fact-fortress-dapp

Zero-Knowledge Proof Framework - Winner of 2023 UC Berkeley ZKP Hackathon
https://pierg.github.io/fact-fortress-web/
3 stars 1 forks source link

Fact Fortress Dapp

Fact Fortress Logo

This repository contains the code for the back-end of Fact Fortress, implemented in Ethereum.

The Fact Fortress framework incorporates smart contracts into its architecture to ensure transparency and accountability in data access. Certified data providers can securely store their sensitive data and set data access policies on how the data must be handled. Data analysts can request access to the data based on these policies to perform an analysis and compute the zero-knowledge proof (ZKP) locally or delegate the data analysis to the smart contract, which returns the ZKP and result directly to them. The framework defines a library of functions that can be computed on data of any form, and each function has an on-chain verifier that can validate a proof submitted by anyone. The verifier ensures that the proof was generated by the function claimed by the data analyst, the data used to generate the proof has not been tampered with, and the claimed result is the correct result of the function applied to the data. Analysts can confidently publish the results together with the proof, which anyone can publicly verify on-chain.

Smart Contract Architecture

What is Fact Fortress

Fact Fortress is a blockchain-based framework that uses zero-knowledge proofs for trustworthy and private fact-checking. It ensures trustworthy data handling and computation by using proofs of data provenance and auditable data access policies. The solution democratizes circuit construction and deployment with a circuit compiler that supports various data formats and source authentication, and facilitates on-chain verification. This preserves sensitive data privacy while ensuring accountability and transparency in data handling and computation. It achieves this by enabling on-chain verification of computation and data provenance without revealing any information about the data itself.

Our framework provides a comprehensive solution that covers the entire process from circuit generation to proof generation, while facilitating collaboration among data analysts, data providers, external verifiers, and policy auditors.

Fact Fortress Overview

For more information, check out our website at: https://pierg.github.io/fact-fortress-web/.

Smart Contracts Backend

Flow

Related Repositories

Prerequisites

Install the backend and the frontend:

git clone git@github.com:pierg/fact-fortress-dapp.git
cd fact-fortress-dapp && pnpm install
git clone git@github.com:pierg/fact-fortress-frontend.git
cd fact-fortress-frontend && pnpm install

Run

Run the DApp

To deploy the backend and the frontend together, run the following command from the root directory:

make run

This command launches the backend, then opens the frontend in the browser (http://localhost:8080).

Independently run the backend

From the root directory, run:

pnpm backend

(By default, the backend runs on port 3000).

A Postman collection is provided to interact with the backend: tools/Postman_collection/Fact_Fortress.postman_collection.json

Independently run the frontend

Unit tests

Once the backend is running (► server started on port 3000 ✓), from the root directory run:

pnpm frontend

Then, open http://localhost:8080 on your browser.

(By default, the backend runs on port 8080).

Run the unit tests

Unit tests

From the root directory, run:

pnpm run test

These tests notably contain an end-to-end flow, from the authorization of data providers to the on-chain verification of the proof of Schnorr signature.

Backend End-to-End Flows

Flow 1. Generate and Verify a Proof

1 | Generate the public/private keys pair

Data providers generate a private/public key pair based on the Grumpkin elliptic curve used by Noir.

WARNING: This action should be performed offline. This endpoint is just a helper. Data providers are expected to generate the keys themselves.
GET http://localhost:3000/key_pair

Example

curl --location 'http://localhost:3000/key_pair'

{
    "public_key": "0x0dd7811f6af9d473c41376affb8660aba00e255c49844b31182f54bc0ab3e2ae1b23bd0e9afdb8275f880934b115057ed86f075048d4d8bd9fa8d92670dc6892",
    "private_key": "ca1a2b52a7405f06f71c03cbaada78559aa86a0e2d01321540012f3762a12818"
}

2 | Authorize the data provider to upload its public key (On-Chain)

Data providers have to be authorized to upload their public keys on the blockchain (otherwise, anyone could do it). To do so, an NFT-based mechanism is used. The owner of the NFT smart contract has to authorize data providers once by sending them NFTs for this purpose.

GET http://localhost:3000/authorize_provider

Example

curl --location 'http://localhost:3000/authorize_provider?address=0x98526c571e324028250B0f5f247Ca4F1b575fadB' \
--header 'from: owner'

{
    "address": "0x98526c571e324028250B0f5f247Ca4F1b575fadB",
    "token_id": "1"
}

3 | Upload the public key (On-Chain)

Data providers upload their public key (for the first time or when they generate a new one). This process enables the verification of the public inputs in the context of the proof of provenance.

PUT http://localhost:3000/publickey

Example

curl --location --request PUT 'http://localhost:3000/publickey?name=ABC&public_key=0x0dd7811f6af9d473c41376affb8660aba00e255c49844b31182f54bc0ab3e2ae1b23bd0e9afdb8275f880934b115057ed86f075048d4d8bd9fa8d92670dc6892' \
--header 'from: providerA'

{
    "name": "ABC",
    "public_key": "0x0dd7811f6af9d473c41376affb8660aba00e255c49844b31182f54bc0ab3e2ae1b23bd0e9afdb8275f880934b115057ed86f075048d4d8bd9fa8d92670dc6892",
    "public_key_version": "0"
}

3b (optional) | Get the public key (On-Chain)

Using this endpoint, anyone (including the verifiers) can get the public keys of data providers.

GET http://localhost:3000/publickey

Example

curl --location 'http://localhost:3000/publickey?name=ABC&version=0'

{
    "public_key": "0x0dd7811f6af9d473c41376affb8660aba00e255c49844b31182f54bc0ab3e2ae1b23bd0e9afdb8275f880934b115057ed86f075048d4d8bd9fa8d92670dc6892"
}

4 | Hash and Sign Data

Data providers have to (SHA-256) hash and sign (using the Grumpkin elliptic curve) the Data.

WARNING: This action should be performed offline. This endpoint is just a helper. Data providers are expected to hash and sign the Data themselves.
POST http://localhost:3000/sign_message

Example

curl --location 'http://localhost:3000/sign_message' \
--header 'Content-Type: application/json' \
--data '{
    "private_key": "98f73670b22c67c1c2b092c5167d1317b661d82db9777751dd6b310efa7c4e17",
    "message": {
        "d1": [ 2, 1, 2, 0, 0, 0, 2, 1, 2, 0, 0, 2, 0, 2, 2, 1, 1, 0, 0, 0, 2, 0, 0, 0, 1, 1, 2, 2, 0, 2, 0, 0],
        "d2": [ 23, 5, 15, 29]
    }
}'

{
    "hash": "e51b88c9ef2ee7a084f676a4d07313895e2850f6789e1bb1aa9845c3d2dd6dea",
    "signature": [
        30,
        149,
        144,
        . . .
        10,
        179,
        103
    ]
}

5 | Store the signature (On-Chain)

Data providers store the signature on the blockchain. That enables the verification of the proof of provenance.

GET http://localhost:3000/upload_signature

Example

curl --location 'http://localhost:3000/upload_signature?public_key=0x077418dea85cb9695990062d64d4d4add4a4d8cbbed3a5f9e5d5f299766bcdf22a10a3540173df59a3e03533011d867c7a8d879dc3819c8c4857ef3a04a6b103' \
--header 'from: ProviderA' \
--header 'Content-Type: application/json' \
--data '{
    "hash": "e51b88c9ef2ee7a084f676a4d07313895e2850f6789e1bb1aa9845c3d2dd6dea",
    "signature": [
        30,
        149,
        144,
        . . .
        10,
        179,
        103
    ]
}'

{
    "stored": true
}

6 | Generate the Proof

Data analysts generate the proof (should be done online).

WARNING: This action should be performed offline. This endpoint is just a helper. Data analysts are expected to generate the proofs themselves.
POST http://localhost:3000/generate_proof

Example

curl --location 'http://localhost:3000/generate_proof?public_key=0x0dd7811f6af9d473c41376affb8660aba00e255c49844b31182f54bc0ab3e2ae1b23bd0e9afdb8275f880934b115057ed86f075048d4d8bd9fa8d92670dc6892' \
--header 'Content-Type: application/json' \
--data '{
    "hash": "e51b88c9ef2ee7a084f676a4d07313895e2850f6789e1bb1aa9845c3d2dd6dea",
    "signature": [
        30,
        149,
        144,
        . . .
        10,
        179,
        103
    ]
}'

[
    13,
    215,
    129,
    . . .
    71,
    13,
    23
]

7 | [ZKP::Proof of Provenance] Verify the Public Inputs (On-Chain)

Verifiers verify the public inputs of the proof of provenance. This is a preliminary step to the verification of the proof of provenance itself (step 8). This step ensures that the data analyst has used the expected public key and signature as public inputs. It can also be performed off-chain.

POST http://localhost:3000/verify_public_inputs

Example

curl --location 'http://localhost:3000/verify_public_inputs?public_key=0x0dd7811f6af9d473c41376affb8660aba00e255c49844b31182f54bc0ab3e2ae1b23bd0e9afdb8275f880934b115057ed86f075048d4d8bd9fa8d92670dc6892' \
--header 'Content-Type: application/json' \
--data '[
    13,
    215,
    129,
    . . .
    71,
    13,
    23
]'

{
    "public_input_match": true
}

8 | [ZKP::Proof of Provenance] Verify the Proof of Provenance (On-Chain)

Verifiers verify the proof of provenance that ensures that the Data comes from a data provider.

POST http://localhost:3000/verify_public_inputs

Example

curl --location 'http://localhost:3000/verify_proof' \
--header 'Content-Type: application/json' \
--data '[
    13,
    215,
    129,
    . . .
    71,
    13,
    23
]'

{
    "valid_proof_of_provenance": true
}

Flow 2. Manage Authorizations (NFTs)

WARNING: Before running this flow, ensure to reset the accounts and authorizations using the frontend helper (implemented for demonstration purposes only): GET http://localhost:3000/reset_accounts

1 | Check All Access Policies (Default Policy)

Get registered access policies when no data analyst has been authorized yet: only the default access policy is returned.

GET http://localhost:3000/all_access_policies

Example

curl --location 'http://localhost:3000/all_access_policies'

{
    "access_policies": [
        "default_policy"
    ]
}

2 | Check Unauthorized Data Provider's Token ID (No Token)

An unauthorized data provider has no token ID

GET http://localhost:3000/provider_token_id

Example

curl --location 'http://localhost:3000/provider_token_id?address=0x98526c571e324028250B0f5f247Ca4F1b575fadB'

{
    "error": "Address does not have a token"
}

3 | Check Unauthorized Data Analyst's Token ID (No Token)

An unauthorized data analyst has no token ID

GET http://localhost:3000/analyst_token_id

Example

curl --location 'http://localhost:3000/analyst_token_id?address=0x5455280E6c20A01de3e846d683562AdeA6891026'

{
    "error": "Address does not have a token"
}

4 | Authorize a Data Provider

Authorize a data provider

GET http://localhost:3000/authorize_provider

Example

curl --location 'http://localhost:3000/analyst_token_id?address=0x5455280E6c20A01de3e846d683562AdeA6891026'

{
    "address": "0x98526c571e324028250B0f5f247Ca4F1b575fadB",
    "token_id": "1"
}

5 | Set all data access policies

Define all data access policies

POST http://localhost:3000/all_access_policies

Example

curl --location 'http://localhost:3000/all_access_policies' \
--header 'from: owner' \
--header 'Content-Type: application/json' \
--data '{
    "access_policies": [
        "TYPE_A",
        "TYPE_B",
        "TYPE_C",
    ]
}'

{
    "access_policies": [
        "TYPE_A",
        "TYPE_B",
        "TYPE_C",
    ]
}

6 | Authorize a Data Analyst

Authorize a data analyst with a set of access policies

POST http://localhost:3000/authorize_analyst

Example

curl --location 'http://localhost:3000/authorize_analyst?address=0x5455280E6c20A01de3e846d683562AdeA6891026' \
--header 'from: owner' \
--header 'Content-Type: application/json' \
--data '{
    "access_policies": [
        "TYPE_A",
        "TYPE_B",
        "TYPE_C",
    ]
}'

{
    "address": "0x98526c571e324028250B0f5f247Ca4F1b575fadB",
    "token_id": "1"
}

7 | Check Authorized Data Analyst's Token ID

Now that the data analyst has been approved, her token ID can be retrieved

GET http://localhost:3000/analyst_token_id

Example

curl --location 'http://localhost:3000/analyst_token_id?address=0x5455280E6c20A01de3e846d683562AdeA6891026'

{
    "address": "0x5455280E6c20A01de3e846d683562AdeA6891026",
    "token_id": "1",
    "access_policies": [
        "TYPE_A",
        "TYPE_B",
        "TYPE_C",
    ]
}

8 | Check All Access Policies

Now that at least on data analyst has been authorized, the set of all access policies has been updated by the smart contract

GET http://localhost:3000/all_access_policies

Example

curl --location 'http://localhost:3000/all_access_policies'

{
    "access_policies": [
        "default_policy",
        "TYPE_A",
        "TYPE_B",
        "TYPE_C",
    ]
}