Skip to content

Commit 67eeb4f

Browse files
Merge pull request #1338 from dfinity/vetkeys-encrypted-chat
feat: vetkeys encrypted chat example
2 parents d94cb5a + 1af1242 commit 67eeb4f

68 files changed

Lines changed: 12864 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Encrypted Chat
2+
3+
| Rust backend | [![](https://icp.ninja/assets/open.svg)](https://icp.ninja/editor?g=https://github.com/dfinity/examples/tree/master/rust/vetkeys/encrypted_chat/rust) |
4+
| --- | --- |
5+
6+
> **Disclaimer**: This is an *unfinished* prototype. DO NOT USE IN PRODUCTION.
7+
8+
The **Encrypted Chat** example demonstrates how to use **[vetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction)** to build an end-to-end encrypted messaging application on the **Internet Computer (IC)**. Messages are encrypted on the sender's device and can only be decrypted by the intended recipients — the backend canister never sees plaintext.
9+
10+
See [SPEC.md](./SPEC.md) for the full technical specification.
11+
12+
## Features
13+
14+
- **End-to-end encrypted messaging**: Messages are encrypted client-side using keys derived from vetKeys.
15+
- **Direct and group chats**: Support for both one-on-one and multi-participant conversations.
16+
- **Symmetric ratchet key rotation**: Keys evolve over time via a symmetric ratchet, providing forward security.
17+
- **Disappearing messages**: Messages expire and are automatically purged from both frontend and backend.
18+
- **Encrypted state recovery**: Users can recover their decryption capability across devices using IBE-encrypted key resharing.
19+
20+
## Setup
21+
22+
### Prerequisites
23+
24+
- [Internet Computer software development kit](https://internetcomputer.org/docs/building-apps/getting-started/install)
25+
- [npm](https://www.npmjs.com/package/npm)
26+
27+
### Deploy the Canisters Locally
28+
29+
From the `rust` folder, run:
30+
```bash
31+
dfx start --background && dfx deploy
32+
```
33+
34+
## Example Components
35+
36+
### Backend
37+
38+
The Rust backend canister manages:
39+
- Chat creation (direct and group) with configurable key rotation and message expiration periods.
40+
- Encrypted message storage and retrieval.
41+
- VetKey derivation for chat encryption keys, with epoch-based rotation.
42+
- Group membership management (add/remove participants).
43+
44+
### Frontend
45+
46+
The frontend is a SvelteKit application providing:
47+
- Internet Identity authentication.
48+
- Real-time encrypted messaging interface.
49+
- Local message caching with IndexedDB.
50+
- Automatic key ratcheting and vetKey epoch management.
51+
52+
To run the frontend in development mode with hot reloading (after running `dfx deploy`):
53+
54+
```bash
55+
cd frontend
56+
npm run dev
57+
```
58+
59+
## Additional Resources
60+
61+
- **[SPEC.md](./SPEC.md)** - Full technical specification of the encryption protocol.
62+
- **[What are VetKeys](https://internetcomputer.org/docs/building-apps/network-features/encryption/vetkeys)** - For more information about VetKeys and VetKD.

rust/vetkeys/encrypted_chat/SPEC.md

Lines changed: 1178 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
test-results
2+
node_modules
3+
4+
# Output
5+
.output
6+
.vercel
7+
.netlify
8+
.wrangler
9+
/.svelte-kit
10+
/build
11+
12+
# OS
13+
.DS_Store
14+
Thumbs.db
15+
16+
# Env
17+
.env
18+
.env.*
19+
!.env.example
20+
!.env.test
21+
22+
# Vite
23+
vite.config.js.timestamp-*
24+
vite.config.ts.timestamp-*
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
engine-strict=true
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Package Managers
2+
package-lock.json
3+
pnpm-lock.yaml
4+
yarn.lock
5+
bun.lock
6+
bun.lockb
7+
8+
# Miscellaneous
9+
/static/
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"useTabs": true,
3+
"singleQuote": true,
4+
"trailingComma": "none",
5+
"printWidth": 100,
6+
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
7+
"overrides": [
8+
{
9+
"files": "*.svelte",
10+
"options": {
11+
"parser": "svelte"
12+
}
13+
}
14+
],
15+
"tailwindStylesheet": "./src/app.css"
16+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# sv
2+
3+
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
4+
5+
## Creating a project
6+
7+
If you're seeing this, you've probably already done this step. Congrats!
8+
9+
```sh
10+
# create a new project in the current directory
11+
npx sv create
12+
13+
# create a new project in my-app
14+
npx sv create my-app
15+
```
16+
17+
## Developing
18+
19+
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
20+
21+
```sh
22+
npm run dev
23+
24+
# or start the server and open the app in a new browser tab
25+
npm run dev -- --open
26+
```
27+
28+
## Building
29+
30+
To create a production version of your app:
31+
32+
```sh
33+
npm run build
34+
```
35+
36+
You can preview the production build with `npm run preview`.
37+
38+
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
test('home page has expected h1', async ({ page }) => {
4+
await page.goto('/');
5+
await expect(page.locator('h1')).toBeVisible();
6+
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import prettier from 'eslint-config-prettier';
2+
import { includeIgnoreFile } from '@eslint/compat';
3+
import js from '@eslint/js';
4+
import svelte from 'eslint-plugin-svelte';
5+
import globals from 'globals';
6+
import { fileURLToPath } from 'node:url';
7+
import ts from 'typescript-eslint';
8+
import svelteConfig from './svelte.config.js';
9+
import path from 'node:path';
10+
11+
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
12+
13+
export default ts.config(
14+
includeIgnoreFile(gitignorePath),
15+
js.configs.recommended,
16+
...ts.configs.recommendedTypeChecked,
17+
...svelte.configs.recommended,
18+
prettier,
19+
...svelte.configs.prettier,
20+
{
21+
languageOptions: {
22+
globals: { ...globals.browser, ...globals.node }
23+
},
24+
rules: {
25+
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
26+
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
27+
'no-undef': 'off'
28+
}
29+
},
30+
{
31+
files: ['**/*.ts'],
32+
languageOptions: {
33+
parser: ts.parser,
34+
parserOptions: {
35+
projectService: true,
36+
tsconfigRootDir: import.meta.dirname
37+
}
38+
}
39+
},
40+
{
41+
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
42+
languageOptions: {
43+
parserOptions: {
44+
extraFileExtensions: ['.svelte'],
45+
parser: ts.parser,
46+
svelteConfig,
47+
projectService: true,
48+
tsconfigRootDir: import.meta.dirname
49+
}
50+
}
51+
},
52+
{
53+
ignores: [
54+
'dist/',
55+
'src/declarations',
56+
'*.config.js',
57+
'*.config.ts',
58+
'*.config.cjs',
59+
'*.config.mjs',
60+
'.svelte-kit',
61+
'e2e/'
62+
]
63+
}
64+
);
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"name": "svelte-latest",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"scripts": {
7+
"build": "npm run build:bindings && vite build",
8+
"dev": "npm run build:bindings && vite build --mode development && vite dev --host",
9+
"build:bindings": "cd scripts && ./gen_bindings.sh",
10+
"preview": "vite preview",
11+
"prepare": "svelte-kit sync || echo ''",
12+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
13+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
14+
"lint": "eslint . && prettier --check .",
15+
"format": "prettier --write .",
16+
"test:e2e": "playwright test",
17+
"test": "npm run test:e2e"
18+
},
19+
"devDependencies": {
20+
"@eslint/compat": "^1.2.5",
21+
"@eslint/js": "^9.18.0",
22+
"@playwright/test": "^1.57.0",
23+
"@rollup/plugin-typescript": "^12.1.4",
24+
"@sveltejs/adapter-auto": "^6.0.0",
25+
"@sveltejs/kit": "^2.53.4",
26+
"@sveltejs/vite-plugin-svelte": "^6.0.0",
27+
"@tailwindcss/vite": "^4.0.0",
28+
"@types/isomorphic-fetch": "^0.0.39",
29+
"eslint": "^9.18.0",
30+
"eslint-config-prettier": "^10.0.1",
31+
"eslint-plugin-svelte": "^3.0.0",
32+
"globals": "^16.0.0",
33+
"prettier": "^3.4.2",
34+
"prettier-plugin-svelte": "^3.3.3",
35+
"prettier-plugin-tailwindcss": "^0.6.11",
36+
"rollup-plugin-css-only": "^4.5.2",
37+
"svelte": "^5.53.6",
38+
"svelte-check": "^4.0.0",
39+
"tailwindcss": "^4.0.0",
40+
"tslib": "^2.8.1",
41+
"typescript": "^5.0.0",
42+
"typescript-eslint": "^8.20.0",
43+
"vite": "^7.3.1",
44+
"vite-plugin-environment": "^1.1.3"
45+
},
46+
"dependencies": {
47+
"@dfinity/agent": "^3.1.0",
48+
"@dfinity/auth-client": "^3.1.0",
49+
"@dfinity/vetkeys": "^0.4.0",
50+
"@melt-ui/svelte": "^0.86.6",
51+
"@skeletonlabs/skeleton": "^3.1.7",
52+
"@skeletonlabs/tw-plugin": "^0.4.1",
53+
"@sveltejs/adapter-static": "^3.0.8",
54+
"base64-js": "^1.5.1",
55+
"cbor-x": "^1.6.0",
56+
"fake-indexeddb": "^6.0.1",
57+
"idb-keyval": "^6.2.2",
58+
"isomorphic-fetch": "^3.0.0",
59+
"js-base64": "^3.7.8",
60+
"lucide-svelte": "^0.536.0",
61+
"sass": "^1.90.0"
62+
}
63+
}

0 commit comments

Comments
 (0)