feature(messages) Checking internal nullifer collisions on messages

This commit is contained in:
Tanner Shaw
2023-08-15 14:27:29 -05:00
parent e3e1c3c578
commit e66619fbe1
4 changed files with 117 additions and 22 deletions

8
package-lock.json generated
View File

@@ -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"

View File

@@ -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",

View File

@@ -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,

View File

@@ -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;
}
})