This commit is contained in:
2023-07-08 13:12:32 -04:00
commit 698f870823
9 changed files with 7712 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
dist/
node_modules/

7362
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

74
package.json Normal file
View File

@@ -0,0 +1,74 @@
{
"name": "discreetly-interfaces",
"version": "0.1.0",
"description": "",
"author": "",
"license": "ISC",
"scripts": {
"build": "rollup --config rollup.config.mjs",
"test": "jest",
"test:debug": "jest --silent=false",
"test:benchmark": "jest --silent=false ./tests/circuit-wrapper.test.ts",
"test:ci": "jest --silent=false --runInBand",
"lint": "eslint --ext .ts,.tsx,.js,.jsx src/ -c .eslintrc.js",
"format": "eslint --ext .ts,.tsx,.js,.jsx src/ -c .eslintrc.js --fix"
},
"keywords": [
"rln",
"rate-limiting-nullifier",
"ethereum",
"circom",
"zk",
"zero-knowledge",
"zk-snarks",
"zero-knowledge-proofs"
],
"publishConfig": {
"access": "public"
},
"main": "./dist/index.node.js",
"module": "./dist/index.mjs",
"browser": {
"./dist/index.node.js": "./dist/index.mjs"
},
"types": "./dist/types/index.d.ts",
"directories": {
"dist": "./dist",
"src": "./src",
"test": "./tests"
},
"files": [
"dist/",
"src/",
"LICENSE",
"README.md"
],
"dependencies": {
"poseidon-lite": "^0.2.0",
"rlnjs": "^3.1.4"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.2",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.2",
"@types/jest": "^29.2.4",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.51.0",
"eslint": "^8.33.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.27.5",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"rollup": "^3.14.0",
"rollup-plugin-cleaner": "^1.0.0",
"rollup-plugin-polyfill-node": "^0.12.0",
"rollup-plugin-typescript2": "^0.35.0",
"rollup-plugin-visualizer": "^5.9.0",
"ts-jest": "^29.0.3",
"tslib": "^2.5.0",
"typescript": "^5.1.6"
}
}

93
rollup.config.mjs Normal file
View File

@@ -0,0 +1,93 @@
/* eslint-disable import/no-extraneous-dependencies */
import typescript from 'rollup-plugin-typescript2'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import nodePolyfills from 'rollup-plugin-polyfill-node'
import replace from '@rollup/plugin-replace'
import { visualizer } from 'rollup-plugin-visualizer'
import cleaner from 'rollup-plugin-cleaner'
import * as fs from 'fs'
const input = 'src/index.ts'
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'))
const banner = `/**
* @module ${pkg.name}
* @version ${pkg.version}
* @file ${pkg.description}
* @copyright Ethereum Foundation 2022
* @license ${pkg.license}
* @see [Github]{@link ${pkg.homepage}}
*/`
const typescriptPlugin = typescript({
tsconfig: 'tsconfig.build.json',
useTsconfigDeclarationDir: true,
})
const visualizerPlugin = visualizer({
emitFile: true,
filename: 'stats.html',
template: 'sunburst',
})
const nodePlugins = [
typescriptPlugin,
// `browser: false` is required for `fs` and other Node.js core modules to be resolved correctly
nodeResolve({ browser: false }),
// To accept commonjs modules and convert them to ES module, since rollup only bundle ES modules by default
commonjs(),
// Parse JSON files and make them ES modules. Required when bundling circomlib
json(),
]
const browserPlugins = [
typescriptPlugin,
replace({
// Replace `process.browser` with `true` to avoid `process is not defined` error
// This is because ffjavascript and snarkjs use `process.browser` to check if it's running in the browser,
// but process is undefined in the browser and referencing `process.browser` causes an error.
// Ref: https://github.com/iden3/ffjavascript/blob/e670bfeb17e80b961eab77e15a6b9eca8e31a0be/src/threadman.js#L43
'process.browser': JSON.stringify(true),
// To avoid unexpected behavior that the warning suggests.
'preventAssignment': true,
}),
// Resolve the import from node_modules.
// `browser: true` is required for `window` not to be undefined
// Ref: https://github.com/iden3/snarkjs/blob/782894ab72b09cfad4dd8b517599d5e7b2340468/src/taskmanager.js#L20-L24
nodeResolve({ browser: true }),
commonjs(),
json(),
// Replace node built-in modules with polyfills
nodePolyfills(),
]
export default [
// Node.js build
{
input,
output: { file: pkg.main, format: 'cjs', banner },
external: Object.keys(pkg.dependencies),
plugins: [
cleaner({
targets: [
'./dist/',
],
}),
...nodePlugins,
visualizerPlugin,
],
},
// Browser build
{
input,
output: { file: pkg.module, format: 'es', banner },
plugins: [
...browserPlugins,
visualizerPlugin,
],
},
]

115
src/index.ts Normal file
View File

@@ -0,0 +1,115 @@
import type { RLNFullProof } from 'rlnjs';
export { str2BigInt, genId, randomBigInt } from './utils';
export type IdentityCommitmentT = bigint;
export enum RoomType {
PUBLIC = 'public',
GATED = 'gated',
PRIVATE = 'private',
SECURE = 'secure'
}
export interface MembershipI {
identityCommitments?: IdentityCommitmentT[];
rlnContract?: RLNContractI;
}
export interface RLNContractI {
address: string;
chainId: number;
}
export interface MessageI {
id?: string; // internal nullifier as string
room?: RLNFullProof['rlnIdentifier'];
message: string;
proof?: RLNFullProof;
}
export interface SystemMessageI {
timestamp: string; // unix epoch time in ms as string
message: string; // plain text message
room?: RLNFullProof['rlnIdentifier']; // optionally send it to one room or all rooms
}
export interface RoomI {
id: RLNFullProof['rlnIdentifier'] | string; // RLN Identifier
name: string; // Readable name
rateLimit?: number; // Milliseconds between messages
membership?: MembershipI; // List of Identity Commitments, or a contract address for an RLN contract
type?: RoomType; // Public or private, if undefinied, assume public
messageHandlerSocket?: string; // Port for websocket connections
}
export interface RoomGroupI {
name: string;
rooms: RoomI[];
}
export interface ServerI {
id: bigint;
name: string;
version?: string;
serverInfoEndpoint: string;
messageHandlerSocket?: string; // Default port for websocket connections
publicMembership?: MembershipI;
roomGroups: RoomGroupI[];
selectedRoom?: RoomI['id'];
}
export class Server {
name: string;
version: string | undefined;
serverInfoEndpoint: string;
messageHandlerSocket: string | undefined;
publicMembership: MembershipI | undefined;
roomGroups: RoomGroupI[];
selectedRoom: string | bigint;
constructor(public server: ServerI) {
this.name = server.name;
this.version = server.version;
this.serverInfoEndpoint = server.serverInfoEndpoint;
this.messageHandlerSocket = server.messageHandlerSocket;
this.publicMembership = server.publicMembership;
this.roomGroups = server.roomGroups;
this.selectedRoom = server.selectedRoom
? server.selectedRoom
: server.roomGroups[0].rooms[0].id;
}
getRoomById(id: string | bigint): RoomI | undefined {
return this.roomGroups
.map((group) => group.rooms)
.flat()
.find((room) => room.id === id);
}
getRoomByName(name: string): RoomI | undefined {
return this.roomGroups
.map((group) => group.rooms)
.flat()
.find((room) => room.name === name);
}
getRoomGroupByName(name: string): RoomGroupI | undefined {
return this.roomGroups.find((group) => group.name === name);
}
setRoomById(id: string | bigint) {
if (this.getRoomById(id)) {
this.selectedRoom = id;
return id;
} else {
return -1;
}
}
getRoomHandlerSocket(id: string | bigint): string | undefined {
const room = this.getRoomById(id);
if (room) {
return room.messageHandlerSocket;
} else {
return this.messageHandlerSocket;
}
}
}

25
src/utils.ts Normal file
View File

@@ -0,0 +1,25 @@
import { poseidon2 } from 'poseidon-lite/poseidon2';
export function str2BigInt(str: string) {
let num = '';
for (let i = 0; i < str.length; i++) {
num += str.charCodeAt(i).toString();
}
return BigInt(num);
}
export function genId(serverID: bigint, roomName: string | bigint | number) {
if (typeof roomName === 'string') {
return poseidon2([serverID, str2BigInt(roomName)]);
}
return poseidon2([serverID, BigInt(roomName)]);
}
export function randomBigInt(bits: number = 253) {
let hexBits = bits / 4;
let hexString = '';
for (let i = 0; i < hexBits; i++) {
hexString += Math.floor(Math.random() * 16).toString(16);
}
return BigInt('0x' + hexString);
}

8
tsconfig.build.json Normal file
View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"rootDir": "./src",
"outDir": "./dist",
"files": [
"src/index.ts",
]
}

21
tsconfig.json Normal file
View File

@@ -0,0 +1,21 @@
{
"compilerOptions": {
"outDir": "./dist",
"target": "ES5",
"module": "ES6",
"moduleResolution": "node",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"noUnusedParameters": true,
"noImplicitAny": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noEmitOnError": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"esModuleInterop": true,
},
"files": [
"./src/index.ts"
]
}

12
tsconfig.test.json Normal file
View File

@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.json",
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitAny": false,
"noImplicitReturns": false,
"noEmitOnError": false,
"include": [
"tests"
],
"exclude": []
}