Skip to content

Zero-Knowledge Proof Framework - Winner of 2023 UC Berkeley ZKP Hackathon

Notifications You must be signed in to change notification settings

pierg/fact-fortress-dapp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 [email protected]:pierg/fact-fortress-dapp.git
cd fact-fortress-dapp && pnpm install
git clone [email protected]: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
  • Input
    • (None)
  • Output
    • public_key Public key based on the Grumpkin curve, used by Noir
    • private_key Random private key

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
  • Caller
    • Owner of the contract
  • Input
    • (Header) from: owner Only the owner of the contract can mint
    • (Parameter) address Address of the data provider about to receive the NFT
  • Output
    • address Address of the data provider having received the NFT
    • token_id NFT token ID

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
  • Caller
    • Provider
  • Input
    • (Header) from: owner Only the data provider owner of an NFT can upload its public key
    • (Parameter) name Name associated with the public key
    • (Parameter) public_key Grumpkin-based public key
  • Output
    • name Name associated with the public key
    • public_key Grumpkin-based public key
    • public_key_version Version of the public key

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
  • Caller
    • Anyone
  • Input
    • (Parameter) name Name associated with the public key
    • (Parameter) version Version of the public key
  • Output
    • public_key Grumpkin-based public key

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
  • Input
    • (Body) private_key Private key associated with the public key that will be used for the proof
    • (Body) message Data to hash and sign
  • Output
    • hash SHA-256 hash of the data (hex)
    • signature Signature of the hash (bytes)

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
  • Caller
    • Provider
  • Input
    • (Parameter) public_key Grumpkin-based public key
    • signature Signature of the hash (bytes)
  • Output
    • stored Status: true if the signature has been stored, false otherwise

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
  • Input
    • (Parameter) public_key Grumpkin-based public key
    • (Body) hash Data hash (hex; copied from step 4)
    • (Body) signature Signature of the hash (bytes; copied from step 4)
  • Output
    • Proof (bytes)

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
  • Input
    • (Parameter) public_key Grumpkin-based public key
    • (Body) Proof (bytes)
  • Output
    • public_input_match: true (public inputs match) or false (public inputs do not match)

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
  • Input
    • (Body) Proof (bytes)
  • Output
    • valid_proof_of_provenance: true (valid proof) or false (invalid proof)

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
  • Input
    • (None)
  • Output
    • access_policies List of all registered data 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
  • Input
    • (parameter) address Address of the data provider
  • Output
    • error When the data provider is unauthorized: Address does not have a token

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
  • Input
    • (parameter) address Address of the data provider
  • Output
    • error When the data provider is unauthorized: Address does not have a token

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
  • Input
    • (header) from: owner Only the owner of the smart contract can call the underlying function
    • (parameter) address Address of the data provider
  • Output
    • address Address of the data provider
    • token_id ID of the NFT sent to the data 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
  • Input
    • (header) from: owner Only the owner of the smart contract can call the underlying function
    • (body) access_policies Set of all access policies
  • Output
    • access_policies Set of 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
  • Input
    • (header) from: owner Only the owner of the smart contract can call the underlying function
    • (parameter) address Address of the data analyst
    • (body) access_policies Set of access policies for this data analyst (should be a subset of all access policies)
  • Output
    • address Address of the data provider
    • token_id ID of the NFT sent to the data provider

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
  • Input
    • (parameter) address Address of the data analyst
  • Output
    • address Address of the data analyst
    • token_id ID of the NFT sent to the data provider
    • access_policies Set of access policies for this data analyst (should be a subset of all access policies)

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
  • Input
    • (None)
  • Output
    • access_policies List of all registered data policies

Example

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

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

About

Zero-Knowledge Proof Framework - Winner of 2023 UC Berkeley ZKP Hackathon

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published