# Project export: LoveBeacon

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: LoveBeacon: Secure matchmaking for your peace of mind. Find your match safely and confidently, using cutting-edge two-person compute technology for a unique love print for secure and private matching.
- Devpost: https://devpost.com/software/lovebeacon
- GitHub: https://github.com/curtischong/2pc-embeddings
- Team: 3 GitHub contributor(s) — Curtis Chong (66 commits), Steven Zhang (21 commits), Alyssa (9 commits)

## Devpost submission (written by the team)

### Overview

Just because relationships are built on trust, doesn't mean matchmaking has to be! 1. Create your personality embedding! 2. Cast your beacon and find your match! 3. Start chatting! Problem: Privacy Matchmaking services that rely on referrals, your friends creating and sharing your profile; Subtle Asian dating, the Aphrodite Project, and more recently, the Resonant have had more successes since they rely on a referral that vouch for your compatibility and social validation to ease the pressure of online dating. However, relying solely on these referrals raises privacy concerns. Value Prop: Escape Big Dating Online dating is dominated by a small number of major companies, often owned by a single corporation. In this environment, users may find themselves trapped in a cycle of perpetual swiping and shallow interactions, leading to frustration and disillusionment with the online dating experience. The overarching goal for these companies becomes maximizing user activity and retention, rather than facilitating meaningful connections or prioritizing user well-being. Solution: Dating x Cryptography x ML LoveBeacon emerges as a beacon of hope in this landscape, offering a fresh approach to online matchmaking that prioritizes user empowerment, security, and genuine connections over short-term metrics like churn rate. By challenging the status quo and placing the interests of its users front and center, LoveBeacon represents a paradigm shift in the world of online dating.

## README (from the GitHub repository)

# LoveBeacon



https://github.com/curtischong/love-beacon/assets/10677873/5a4e6303-77fc-4385-9e19-8460bdfac9f0



Love Beacon is a MatchMaking app. After filling out your profile, a language model converts it into an embedding. A match occurs if you have a high cosine similarity with others. At no point does your embedding leave your device or is shared with other people.

So how are we able to calculate cosine similarity? Don't the two vectors need to be on the same computer to do the multiply and add operations?

Well... Two Party Computation (2PC) solves this problem! (computing on multiple private inputs)

![Dot Product Circuit](circuit.jpeg)

This is an implementation of Yao's Garbled Circuits (a 2PC protocol). The main code was based on https://github.com/tdjsnelling/garbled-circuits/tree/master. It was very helpful because they figured out how to use Verilog to define the circuits.

However, I modified it for optimization reasons AND to make the 2PC happen between different browser clients (rather than in just one nodeJS process)

### Why 2PC?
- Cause the tech is cool
  - Note: I don't believe that 2PC is that useful because we can have privacy-preserving computing using a Trusted Execution Environment (TEE). But I did have a REALLY fun time writing and debugging this over TreeHacks.
- I listened to Barry Whitehat's talk on [2PC is for Lovers](https://www.youtube.com/watch?v=PzcDqegGoKI) and have wanted to implement it ever since.

### Why a Matchmaking app?
- We were inspired by our friends at Resonant for hosting a matchmaking round last week (during Valentine's!)
- We wanted to pressure ourselves to deploy on mobile so it doesn't take too much compute
- We wanted to deploy this during Treehacks and see people use it! (ran out of time)

### Optimizations Used
- 4-bit quantization
- "Chunking" the dot product calculation 10 dimensions at a time. We first calculate the similarity for the first 10 dimensions, then the next 10, etc. until we've calculated similarity for all dimensions of both vectors.
  - At the end, we do a sum of these dot product chunks. It DOES leak info (you know the dot product of every 10 dimensions of the embedding), but this makes the circuit much smaller
- Reducing the number of back-and-forth calls during the Oblivious Transfer (there's still room for improvement)
- Using only the first 50 dimensions of the dimension vector (ikik. This loses a lot of info)
- Fast modular exponentiation


### Getting Started

In 3 diff terminals, run:

```
cd webrtc/client_server
python3 -m venv venv
pip install -r requirements.txt
uvicorn api:app --host 0.0.0.0 --port 8000
```

```
cd webrtc/user_server
npm i
npm run dev
```

```
cd webrtc/websocket_server
npm i
npm start
```

Now open `http://localhost:3000/` in two tabs: one normally and one in Incognito mode


Now fill out "Find Your Match" in both pages

Now click Activate Beacon in both windows.

Finally, click on "Check compatibility with Bob/Alice" on one of the windows
- This will trigger the 2PC protocol. The person that triggers the protocol is Alice (in the code).

- Note: I suggest opening the console to see the logs!


## Detected evidence (automated analysis)

Indexed codebase: 39 recognized source files, 164 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- Hugging Face (technology) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- PyTorch (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (62 of 62)

```
.gitignore
README.md
webrtc/client_server/.gitignore
webrtc/client_server/api.py
webrtc/client_server/curl.sh
webrtc/client_server/embeddings.py
webrtc/client_server/README.md
webrtc/client_server/requirements.txt
webrtc/client_server/test.js
webrtc/user_server/.eslintrc.json
webrtc/user_server/.gitignore
webrtc/user_server/2pc/index.html
webrtc/user_server/2pc/package.json
webrtc/user_server/2pc/README.md
webrtc/user_server/2pc/script.js
webrtc/user_server/2pc/src/calculate.ts
webrtc/user_server/2pc/src/circuit/evaluate.ts
webrtc/user_server/2pc/src/circuit/garble.ts
webrtc/user_server/2pc/src/circuit/gates.ts
webrtc/user_server/2pc/src/circuitStr.ts
webrtc/user_server/2pc/src/index.ts
webrtc/user_server/2pc/src/oblivious-transfer.ts
webrtc/user_server/2pc/src/utils.ts
webrtc/user_server/2pc/src/verilog.ts
webrtc/user_server/2pc/styles.css
webrtc/user_server/2pc/tsconfig.json
webrtc/user_server/2pc/verilog/dotproduct/dotproduct.v
webrtc/user_server/2pc/verilog/dotproduct/dotproduct.yosys
webrtc/user_server/2pc/verilog/dotproduct/netlist.json
webrtc/user_server/2pc/verilog/dotproduct/out.v
webrtc/user_server/2pc/verilog/fulladd/fulladd.v
webrtc/user_server/2pc/verilog/fulladd/fulladd.yosys
webrtc/user_server/2pc/verilog/fulladd/netlist.json
webrtc/user_server/2pc/verilog/fulladd/out.v
webrtc/user_server/2pc/verilog/millionaire/millionaire.v
webrtc/user_server/2pc/verilog/millionaire/millionaire.yosys
webrtc/user_server/2pc/verilog/millionaire/netlist.json
webrtc/user_server/2pc/verilog/millionaire/out.v
webrtc/user_server/app/globals.css
webrtc/user_server/app/landing/page.tsx
webrtc/user_server/app/layout.tsx
webrtc/user_server/app/match/page.tsx
webrtc/user_server/app/page.tsx
webrtc/user_server/app/swipe/page.tsx
webrtc/user_server/app/test/page.tsx
webrtc/user_server/components/SwipeCards.tsx
webrtc/user_server/components/TabIcon.tsx
webrtc/user_server/components/Tabs.tsx
webrtc/user_server/components/ToggleBeacon.tsx
webrtc/user_server/components/WebRTC.tsx
webrtc/user_server/next.config.mjs
webrtc/user_server/package.json
webrtc/user_server/postcss.config.js
webrtc/user_server/README.md
webrtc/user_server/server.js
webrtc/user_server/tailwind.config.ts
webrtc/user_server/tsconfig.json
webrtc/user_server/types.ts
webrtc/websocket_server/index.html
webrtc/websocket_server/package.json
webrtc/websocket_server/script.js
webrtc/websocket_server/server.js
```

### Dependencies

- webrtc/client_server/requirements.txt: annotated-types@==0.6.0, anyio@==4.2.0, certifi@==2024.2.2, charset-normalizer@==3.3.2, click@==8.1.7, exceptiongroup@==1.2.0, fastapi@==0.109.2, filelock@==3.13.1, fsspec@==2024.2.0, h11@==0.14.0, huggingface-hub@==0.20.3, idna@==3.6, Jinja2@==3.1.3, MarkupSafe@==2.1.5, mpmath@==1.3.0, networkx@==3.2.1, numpy@==1.26.4, packaging@==23.2, pydantic@==2.6.1, pydantic_core@==2.16.2, PyYAML@==6.0.1, regex@==2023.12.25, requests@==2.31.0, safetensors@==0.4.2, sniffio@==1.3.0, starlette@==0.36.3, sympy@==1.12, tokenizers@==0.15.2, torch@==2.2.0, tqdm@==4.66.2, transformers@==4.37.2, typing_extensions@==4.9.0, urllib3@==2.2.0, uvicorn@==0.27.1, websockets@==12.0
- webrtc/user_server/2pc/package.json: @types/node@^20.11.16, @typescript-eslint/eslint-plugin@^6.21.0, @typescript-eslint/parser@^6.21.0, concurrently@^8.2.2, crypto-browserify@^3.12.0, eslint@^8.56.0, eslint-config-prettier@^9.1.0, eslint-plugin-prettier@^5.1.3, nodemon@^3.0.3, prettier@^3.2.5, typescript@^5.3.3
- webrtc/user_server/package.json: @types/canvas-confetti@^1.6.4, @types/node@^20, @types/react@^18, @types/react-dom@^18, autoprefixer@^10.0.1, canvas-confetti@^1.9.2, crypto-browserify@^3.12.0, eslint@^8, eslint-config-next@14.1.0, next@14.1.0, postcss@^8, react@^18, react-dom@^18, react-icons@^5.0.1, react-spring@^9.7.3, react-use-gesture@^9.1.3, react-use-websocket@^3.0.0, tailwindcss@^3.3.0, typescript@^5.3.3, uuid@^9.0.1, ws@^8.16.0
- webrtc/websocket_server/package.json: typescript@^5.3.3, ws@^8.16.0

### Recent commits (newest first)

- explain why the output is signed
- explain why I have 4 inputs
- explain why I'm using quantization
- Update README.md
- Update README.md
- Update README.md
- add video of the app
- move circuit down
- fix grammar
- added readme
- adding readme
- Merge pull request #6 from curtischong/use-real-embeddings
- fix dot product on href
- wip use real embeddings
- panikkkkkkkkkk
- alice sends bob final ans
- Merge pull request #5 from curtischong/its-a-match-page
- Merge branch 'main' into its-a-match-page
- emboed on swipe redirect
- Merge pull request #4 from curtischong/try-cosine

## Key source files (fetched from GitHub, selected and truncated for size)

### webrtc/websocket_server/package.json

```
{
  "name": "webrtc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ws": "^8.16.0"
  },
  "devDependencies": {
    "typescript": "^5.3.3"
  }
}

```

### webrtc/client_server/requirements.txt

```
annotated-types==0.6.0
anyio==4.2.0
certifi==2024.2.2
charset-normalizer==3.3.2
click==8.1.7
exceptiongroup==1.2.0
fastapi==0.109.2
filelock==3.13.1
fsspec==2024.2.0
h11==0.14.0
huggingface-hub==0.20.3
idna==3.6
Jinja2==3.1.3
MarkupSafe==2.1.5
mpmath==1.3.0
networkx==3.2.1
numpy==1.26.4
packaging==23.2
pydantic==2.6.1
pydantic_core==2.16.2
PyYAML==6.0.1
regex==2023.12.25
requests==2.31.0
safetensors==0.4.2
sniffio==1.3.0
starlette==0.36.3
sympy==1.12
tokenizers==0.15.2
torch==2.2.0
tqdm==4.66.2
transformers==4.37.2
typing_extensions==4.9.0
urllib3==2.2.0
uvicorn==0.27.1
websockets==12.0

```

### webrtc/user_server/package.json

```
{
  "name": "webrtc-demo",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "canvas-confetti": "^1.9.2",
    "crypto-browserify": "^3.12.0",
    "next": "14.1.0",
    "react": "^18",
    "react-dom": "^18",
    "react-icons": "^5.0.1",
    "react-spring": "^9.7.3",
    "react-use-gesture": "^9.1.3",
    "react-use-websocket": "^3.0.0",
    "uuid": "^9.0.1",
    "ws": "^8.16.0"
  },
  "devDependencies": {
    "@types/canvas-confetti": "^1.6.4",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.0.1",
    "eslint": "^8",
    "eslint-config-next": "14.1.0",
    "postcss": "^8",
    "tailwindcss": "^3.3.0",
    "typescript": "^5.3.3"
  }
}

```

### webrtc/user_server/2pc/package.json

```
{
    "name": "garbled-circuits",
    "version": "1.0.0",
    "description": "A toy garbled circuits MPC implementation",
    "main": "src/index.js",
    "repository": "https://github.com/tdjsnelling/garbled-circuits",
    "author": "Tom Snelling",
    "license": "MIT",
    "private": false,
    "scripts": {
        "build": "tsc",
        "dev": "concurrently --passthrough-arguments --kill-others \"yarn build --watch\" \"nodemon --enable-source-maps dist/index.js {1}\"",
        "start": "node dist/index.js"
    },
    "devDependencies": {
        "@types/node": "^20.11.16",
        "@typescript-eslint/eslint-plugin": "^6.21.0",
        "@typescript-eslint/parser": "^6.21.0",
        "concurrently": "^8.2.2",
        "eslint": "^8.56.0",
        "eslint-config-prettier": "^9.1.0",
        "eslint-plugin-prettier": "^5.1.3",
        "nodemon": "^3.0.3",
        "prettier": "^3.2.5",
        "typescript": "^5.3.3"
    },
    "dependencies": {
        "crypto-browserify": "^3.12.0"
    }
}

```

### webrtc/user_server/server.js

```javascript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    // Broadcast any received message to all clients
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

console.log('Server running on port 8080'); 
```

### webrtc/websocket_server/server.js

```javascript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    // Broadcast any received message to all clients
    wss.clients.forEach(function each(client) {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

console.log('Server running on port 8080'); 
```

### webrtc/user_server/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  );
}

```

### webrtc/user_server/app/page.tsx

```typescript
// pages/index.tsx
'use client';
import React from 'react';
import Image from 'next/image';

export default function Home() {
  return (
    <div className="flex flex-col items-center bg-pink-50">
      <div className="text-center p-12">
        <h1 className="text-5xl font-bold text-pink-600">
          Welcome to LoveBeacon ❤️
        </h1>
        <p className="mt-3 text-pink-700">
          Finding love by securely sharing your {' '}
          <code className="p-1 font-mono text-sm bg-pink-200 rounded-md">
            personality embeddings
          </code>
        </p>
        <div className="mt-6">
          <a
        href="swipe"
            className="px-6 py-3 bg-pink-500 text-white rounded-md text-lg font-medium hover:bg-pink-700 transition duration-200 ease-in-out"
          >
            Find Your Match
          </a>
        </div>
      </div>

      {/* Technology explanation section */}
      <div className="w-full px-6 py-16 bg-pink-100 border-t-4 border-pink-300">
        <div className="max-w-4xl mx-auto bg-white rounded-xl shadow-lg overflow-hidden">
          <div className="md:flex">
            <div className="md:flex-shrink-0">
              {/* Ensure the path to the image is correct */}
              <Image
                src="/lighthouse.png"
                alt="Love image"
                width={192}  // Adjust as needed
                height={192} // Adjust as needed
                objectFit="cover"
                className="h-48 w-full object-cover md:h-full md:w-48"
              />
            </div>
            <div className="p-8">
              <h2 className="text-3xl text-pink-600 font-semibold mb-6">
                How LoveBeacon Works
              </h2>
              <p className="text-pink-700 mb-4">
                LoveBeacon uses two-person compute technology to match you with potential partners in a private, secure way. It's like a digital cupid working behind the scenes. Here's how it connects hearts:
              </p>
              <ul className="list-disc list-inside text-pink-700 mb-4 space-y-2">
                <li>Upload your profile and let LoveBeacon create your unique love print.</li>
                <li>Our matchmaking algorithm weaves its magic to find your perfect match.</li>
                <li>Privacy-first approach ensures your personal details are always under wraps.</li>
                <li>Receive curated matches that are in tune with your heart's desires.</li>
              </ul>
              <p className="text-pink-700">
                With LoveBeacon, finding your soulmate is safe, private, and enchanting.
              </p>
            </div>
          </div>
        </div>
      </div>

    </div>
  );
}

```

### webrtc/user_server/app/landing/page.tsx

```typescript
'use client'
import React, { useState, useCallback, useEffect } from 'react';

import Tabs from '../../components/Tabs';


export default function LandingPage() {
  return (
    <section className="text-center bg-pink-100 py-12 px-4 flex flex-col justify-center items-center min-h-screen">
      <Tabs />
    </section>
  );
}


```

### webrtc/user_server/app/match/page.tsx

```typescript
// app/match/page.tsx
'use client';

import React, { useEffect, useState } from 'react';
import confetti from 'canvas-confetti';
import { WebSocketDemo } from '@/components/WebRTC';

const MatchPage = () => {
    const [currentPerson, setCurrentPerson] = useState('')
    const [showWebSocket, setShowWebSocket] = useState(false);

    useEffect(() => {
        // Trigger confetti on component mount
        confetti({
            particleCount: 150,
            spread: 70,
            origin: { y: 0.6 },
        });
        // Show WebSocketDemo after 3 seconds
        const timer = setTimeout(() => {
            setShowWebSocket(true);
        }, 3000);
        return () => clearTimeout(timer);
    }, []);

    return (
        <div className="flex flex-col items-center justify-center min-h-screen bg-pink-100">
            <div className="text-center">
                <h1 className="text-4xl font-bold text-pink-600 mb-4">It's a Match!</h1>
                <p className="text-2xl text-pink-700 mb-8">💖✨🎉</p>
                <div className="animate-pulse text-5xl">
                    💕
                </div>
            </div>
            {showWebSocket && <WebSocketDemo currentPerson={currentPerson} setCurrentPerson={setCurrentPerson} />}

        </div>
    );
};

export default MatchPage;

```

[28 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]