mirror of
https://github.com/Discreetly/server.git
synced 2026-01-09 12:37:58 -05:00
feature(messages) Checking internal nullifer collisions on messages
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -14,7 +14,7 @@
|
||||
"body-parser": "^1.20.2",
|
||||
"cors": "^2.8.5",
|
||||
"discreetly-claimcodes": "^1.1.5",
|
||||
"discreetly-interfaces": "^0.1.29",
|
||||
"discreetly-interfaces": "^0.1.31",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
@@ -3466,9 +3466,9 @@
|
||||
"integrity": "sha512-pQueoGtBJk/FrTfGzepjqYfTLaymS+4t11byI4OcfjWQOagRsD7dtavGcowTVQ7Ib/vjKna5T+71WcgWZaAWuA=="
|
||||
},
|
||||
"node_modules/discreetly-interfaces": {
|
||||
"version": "0.1.29",
|
||||
"resolved": "https://registry.npmjs.org/discreetly-interfaces/-/discreetly-interfaces-0.1.29.tgz",
|
||||
"integrity": "sha512-3R63KkmB+wFKFFzD9DixX3VDoLCYkDuMQZucAItmXbjE+0tFgmrK683a1/WBI9VkBhARip6HsVNrjzaGqdR1Aw==",
|
||||
"version": "0.1.31",
|
||||
"resolved": "https://registry.npmjs.org/discreetly-interfaces/-/discreetly-interfaces-0.1.31.tgz",
|
||||
"integrity": "sha512-XRuQee/hmX0I3NkXkNZEzZ+6ZLLVyjjyv4HzcN2H1HJWnhmBsb0BozHifYd22Xk83LuXp7rojnK9qrAHwy1k9g==",
|
||||
"dependencies": {
|
||||
"poseidon-lite": "^0.2.0",
|
||||
"rlnjs": "^3.1.4"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"body-parser": "^1.20.2",
|
||||
"cors": "^2.8.5",
|
||||
"discreetly-claimcodes": "^1.1.5",
|
||||
"discreetly-interfaces": "^0.1.29",
|
||||
"discreetly-interfaces": "^0.1.31",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
|
||||
@@ -170,11 +170,11 @@ export async function createRoom(
|
||||
const mockUsers: string[] = genMockUsers(approxNumMockUsers);
|
||||
const roomData = {
|
||||
where: {
|
||||
roomId: genId(serverConfig.id, name).toString()
|
||||
roomId: genId(serverConfig.id as bigint, name).toString()
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
roomId: genId(serverConfig.id, name).toString(),
|
||||
roomId: genId(serverConfig.id as bigint, name).toString(),
|
||||
name: name,
|
||||
rateLimit: rateLimit,
|
||||
userMessageLimit: userMessageLimit,
|
||||
|
||||
@@ -1,16 +1,108 @@
|
||||
import { getRoomByID } from './db';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { MessageI } from 'discreetly-interfaces';
|
||||
import { getRoomByID } from "./db";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { MessageI } from "discreetly-interfaces";
|
||||
import { shamirRecovery } from "../crypto/shamirRecovery";
|
||||
import { RLNFullProof } from "rlnjs";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export type StrBigInt = string | bigint;
|
||||
|
||||
export type Proof = {
|
||||
pi_a: StrBigInt[];
|
||||
pi_b: StrBigInt[][];
|
||||
pi_c: StrBigInt[];
|
||||
protocol: string;
|
||||
curve: string;
|
||||
};
|
||||
|
||||
export type RLNPublicSignals = {
|
||||
x: StrBigInt;
|
||||
externalNullifier: StrBigInt;
|
||||
y: StrBigInt;
|
||||
root: StrBigInt;
|
||||
nullifier: StrBigInt;
|
||||
};
|
||||
|
||||
export type RLNSNARKProof = {
|
||||
proof: Proof;
|
||||
publicSignals: RLNPublicSignals;
|
||||
};
|
||||
|
||||
interface CollisionCheckResult {
|
||||
collision: boolean;
|
||||
secret?: bigint;
|
||||
oldMessage?: MessageI;
|
||||
}
|
||||
|
||||
export async function checkRLNCollision(
|
||||
roomId: string,
|
||||
message: MessageI
|
||||
): Promise<CollisionCheckResult> {
|
||||
return new Promise((res, rej) => {
|
||||
prisma.rooms
|
||||
.findFirst({
|
||||
where: { roomId },
|
||||
include: {
|
||||
epochs: {
|
||||
where: { epoch: String(message.epoch) },
|
||||
include: {
|
||||
messages: {
|
||||
where: { messageId: message.messageId },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.then((oldMessage) => {
|
||||
if (!message.proof) {
|
||||
throw new Error("Proof not provided");
|
||||
}
|
||||
if (!oldMessage) {
|
||||
res({ collision: false } as CollisionCheckResult);
|
||||
} else {
|
||||
const oldMessageProof = JSON.parse(
|
||||
oldMessage.epochs[0].messages[0].proof
|
||||
) as RLNFullProof;
|
||||
const oldMessagex2 = BigInt(
|
||||
oldMessageProof.snarkProof.publicSignals.x
|
||||
);
|
||||
const oldMessagey2 = BigInt(
|
||||
oldMessageProof.snarkProof.publicSignals.y
|
||||
);
|
||||
|
||||
let proof: RLNFullProof;
|
||||
|
||||
if (typeof message.proof === "string") {
|
||||
proof = JSON.parse(message.proof) as RLNFullProof;
|
||||
} else {
|
||||
proof = message.proof as RLNFullProof;
|
||||
}
|
||||
const [x1, y1] = [
|
||||
BigInt(proof.snarkProof.publicSignals.x),
|
||||
BigInt(proof.snarkProof.publicSignals.y),
|
||||
];
|
||||
const [x2, y2] = [oldMessagex2, oldMessagey2];
|
||||
|
||||
const secret = shamirRecovery(x1, x2, y1, y2);
|
||||
|
||||
res({
|
||||
collision: true,
|
||||
secret,
|
||||
oldMessage: oldMessage.epochs[0].messages[0] as MessageI,
|
||||
} as CollisionCheckResult);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addMessageToRoom(roomId: string, message: MessageI): Promise<unknown> {
|
||||
if (!message.epoch) {
|
||||
throw new Error('Epoch not provided');
|
||||
throw new Error("Epoch not provided");
|
||||
}
|
||||
return prisma.rooms.update({
|
||||
where: {
|
||||
roomId: roomId
|
||||
roomId: roomId,
|
||||
},
|
||||
data: {
|
||||
epochs: {
|
||||
@@ -18,15 +110,15 @@ function addMessageToRoom(roomId: string, message: MessageI): Promise<unknown> {
|
||||
epoch: String(message.epoch),
|
||||
messages: {
|
||||
create: {
|
||||
message: message.message ? message.message.toString() : '',
|
||||
messageId: message.messageId ? message.messageId.toString() : '',
|
||||
message: message.message ? message.message.toString() : "",
|
||||
messageId: message.messageId ? message.messageId.toString() : "",
|
||||
proof: JSON.stringify(message.proof),
|
||||
roomId: roomId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
roomId: roomId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,7 +126,10 @@ export function createMessage(roomId: string, message: MessageI): boolean {
|
||||
getRoomByID(roomId)
|
||||
.then((room) => {
|
||||
if (room) {
|
||||
// Todo This should check that there is no duplicate messageId with in this room and epoch, if there is, we need to return an error and reconstruct the secret from both messages, and ban the user
|
||||
// Todo This should check that there is no duplicate messageId with in this room and epoch,
|
||||
// if there is, we need to return an error and
|
||||
// reconstruct the secret from both messages, and ban the user
|
||||
|
||||
addMessageToRoom(roomId, message)
|
||||
.then((roomToUpdate) => {
|
||||
console.log(roomToUpdate);
|
||||
@@ -45,7 +140,7 @@ export function createMessage(roomId: string, message: MessageI): boolean {
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
console.log('Room not found');
|
||||
console.log("Room not found");
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user