Skip to content
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
32 changes: 15 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
# Encrypted Dataroom Management (eDRM)
# ZDrive

Trustless, encrypted filesharing where access is enforced via FHE (Fully Homomorphic Encryption). Nobody can see who has access to what. Documents live on Filecoin via Storacha.
Encrypted file sharing where access is enforced via FHE (Fully Homomorphic Encryption). Nobody can see who has access to what. Documents live on Filecoin via Storacha.

## The Problem

Data rooms are essential to every investment deal, yet the market (\$3-4B TAM, led by Intralinks and Datasite) charges \$15-50k+ per deal for what is fundamentally access control on a file share.
Securely sharing files today means trusting a vendor with your data. Whether it's a data room for a deal (\$3-4B TAM, led by Intralinks and Datasite at \$15-50k+ per deal), confidential project files, or anything you want to share privately, you're relying on trust assumptions of the vendors and members that operate these platforms.

Often we need to rely on trust assumptions of the vendors and the members that operate on these data rooms.

**Alternatively, it's a way to securely share documents with your friends that no-one else can access!**
**ZDrive replaces vendor trust with math.**

## The Solution

eDRM replaces vendor trust with math. Document encryption and access control are enforced on-chain via [Zama](https://docs.zama.org/protocol) FHE and [Storacha](https://storacha.network).
ZDrive uses [Zama](https://docs.zama.org/protocol) FHE for on-chain encrypted access control and [Storacha](https://storacha.network) for decentralized storage. No intermediary can read your files or see who has access, and the audit log is clean and verifiable.

No intermediary can read dealflow files or see who has access and the audit log is clean and verifiable.
Can be used for simple sharing documents to confidential fundraising data rooms, M&A due diligence, investor updates.

## How It Works

1. Company creates a data room: FHE-encrypted room key generated on-chain
2. Company uploads documents: encrypted client-side with AES-256-GCM derived from the room key, stored on Filecoin via Storacha, encrypted CID recorded on-chain
3. Company grants access to investor/auditor addresses: `FHE.allow(roomKey, investor)` lets them decrypt
4. Investor/Auditor connects wallet: decrypts FHE room key, derives AES key, downloads and decrypts documents from Storacha
1. Create a folder: FHE-encrypted folder keys generated on-chain
2. Upload documents: encrypted client-side with AES-256-GCM derived from the folder key, stored on Filecoin via Storacha, encrypted CID recorded on-chain
3. Grant access to collaborator addresses: lets them decrypt locally.
4. Collaborator connects wallet: decrypts FHE folder key, derives AES key, downloads and decrypts documents.

For the full encryption flow, key hierarchy, and contract interface, see [Technical Architecture](docs/ARCHITECTURE.md).

Expand Down Expand Up @@ -86,19 +84,19 @@ This runs:
#### Storacha setup
If it's too much effort to setup Storacha ask for keys from: petros@obolos.io

The dapp encrypts files client-side and uploads them to Filecoin via [Storacha](https://storacha.network).
The dapp encrypts files client-side and uploads them to Filecoin via [Storacha](https://storacha.network).

Make an agent key and a delegation proof:

```bash
# 1. Install the CLI
npm i -g @storacha/cli

# 2. Login. Then CONFIRM email link
# 2. Login. CONFIRM email link
npx @storacha/cli login your@email.com

# 3. Create a space (or use an existing one from `npx @storacha/cli space ls`)
npx @storacha/cli space create my-data-room
# 3. Create a space (or use an existing with `npx @storacha/cli space ls`)
npx @storacha/cli space create my-zdrive

# 4. Generate an agent key. prints a DID and a private key
npx @storacha/cli key create
Expand All @@ -109,7 +107,7 @@ npx @storacha/cli delegation create <did:key:from-step-4> \
--can store/add --can upload/add --can filecoin/offer \
--can space/blob/add --can space/index/add \
--base64
# copy the base64 string as VITE_STORACHA_PROOF
# copy the base64 string as VITE_STORACHA_PROOF
```

Then set both values in `dapp/.env`:
Expand Down
2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "encrypted-dataroom-contracts",
"name": "zdrive-contracts",
"version": "0.1.0",
"private": true,
"scripts": {
Expand Down
8 changes: 4 additions & 4 deletions dapp/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
#
# Setup (one-time):
# 1. npm i -g @storacha/cli
# 2. w3 login <your-email> # confirm via email
# 3. w3 space create my-data-room # creates a space
# 4. w3 key create # prints DID + private key
# 2. npx @storacha/cli login <your-email> # confirm via email
# 3. npx @storacha/cli space create my-zdrive # creates a space
# 4. npx @storacha/cli key create # prints DID + private key
# → copy the private key (MgC…) as VITE_STORACHA_KEY
# 5. w3 delegation create <did:key:from-step-4> \
# 5. npx @storacha/cli delegation create <did:key:from-step-4> \
# --can store/add --can upload/add --can filecoin/offer \
# --can space/blob/add --can space/index/add \
# --base64
Expand Down
11 changes: 10 additions & 1 deletion dapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/edrm-mark.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>eDRM</title>
<title>ZDrive</title>
<meta name="description" content="Encrypted file sharing with on-chain access control. Data rooms, due diligence, confidential collaboration — trustlessly." />
<meta property="og:title" content="ZDrive" />
<meta property="og:description" content="Encrypted file sharing with on-chain access control. Data rooms, due diligence, confidential collaboration — trustlessly." />
<meta property="og:type" content="website" />
<meta property="og:image" content="/og-image.svg" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="ZDrive" />
<meta name="twitter:description" content="Encrypted file sharing with on-chain access control. Data rooms, due diligence, confidential collaboration — trustlessly." />
<meta name="twitter:image" content="/og-image.svg" />
<script async src="https://www.googletagmanager.com/gtag/js?id=G-R8JYXG1CLC"></script>
<script>
window.dataLayer = window.dataLayer || [];
Expand Down
4 changes: 1 addition & 3 deletions dapp/public/edrm-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions dapp/public/og-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions dapp/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Layout from "./components/Layout";
import Landing from "./pages/Landing";
import Dashboard from "./pages/Dashboard";
import Room from "./pages/Room";
import InvestorView from "./pages/InvestorView";
import NotFound from "./pages/NotFound";

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Landing />} />
<Route element={<Layout />}>
<Route path="/" element={<Dashboard />} />
<Route path="/room/:roomId" element={<Room />} />
<Route path="/investor" element={<InvestorView />} />
<Route path="/drive" element={<Dashboard />} />
<Route path="/drive/:roomId" element={<Room />} />
<Route path="/drive/:roomId/folder/:folderId" element={<Room />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
2 changes: 1 addition & 1 deletion dapp/src/assets/11155111.contracts.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"EncryptedDataRoom": "0x24c0857bba4d85625954737cc4b27f5a9daa7fce"
"EncryptedDataRoom": "0x5b21eb6e20bf551e131558b10084954543eece66"
}
2 changes: 1 addition & 1 deletion dapp/src/assets/31337.contracts.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"EncryptedDataRoom": "0xd84379ceae14aa33c123af12424a37803f885889"
"EncryptedDataRoom": "0x5fbdb2315678afecb367f032d93f642f64180aa3"
}
64 changes: 62 additions & 2 deletions dapp/src/assets/abis/EncryptedDataRoom.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
[
{
"type": "function",
"name": "MAX_BATCH_SIZE",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "NO_PARENT",
Expand Down Expand Up @@ -40,6 +53,19 @@
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "confidentialProtocolId",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "createFolder",
Expand Down Expand Up @@ -271,7 +297,7 @@
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
"internalType": "euint256"
}
],
"stateMutability": "view"
Expand Down Expand Up @@ -312,6 +338,25 @@
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "hasAccess",
"inputs": [
{
"name": "roomId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "rekeyRoom",
Expand Down Expand Up @@ -479,7 +524,7 @@
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
"internalType": "ebool"
}
],
"stateMutability": "view"
Expand Down Expand Up @@ -578,11 +623,21 @@
"name": "AlreadyMember",
"inputs": []
},
{
"type": "error",
"name": "BatchTooLarge",
"inputs": []
},
{
"type": "error",
"name": "CannotNestDeeper",
"inputs": []
},
{
"type": "error",
"name": "InvalidAddress",
"inputs": []
},
{
"type": "error",
"name": "IsParentRoom",
Expand Down Expand Up @@ -617,5 +672,10 @@
"type": "error",
"name": "Unauthorized",
"inputs": []
},
{
"type": "error",
"name": "ZamaProtocolUnsupported",
"inputs": []
}
]
8 changes: 1 addition & 7 deletions dapp/src/components/BrandMark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,9 @@ export function BrandMark({ className = "h-7 w-7" }: { className?: string }) {
>
<rect x="2.5" y="2.5" width="27" height="27" rx="9" fill="currentColor" opacity="0.1" />
<path
d="M10 9.5H20.5V12H13V15.25H19.5V17.75H13V22.5H10V9.5Z"
d="M9.5 9.5H22.5V13H15.5L22.5 19V22.5H9.5V19H16.5L9.5 13V9.5Z"
fill="currentColor"
/>
<path
d="M21.75 12.75C23.82 12.75 25.5 14.43 25.5 16.5C25.5 18.57 23.82 20.25 21.75 20.25H19.5V17.95H21.6C22.39 17.95 23.03 17.3 23.03 16.5C23.03 15.7 22.39 15.05 21.6 15.05H19.5V12.75H21.75Z"
fill="currentColor"
opacity="0.82"
/>
<circle cx="23.8" cy="23.2" r="2.2" fill="currentColor" opacity="0.92" />
</svg>
);
}
Loading
Loading