Skip to content

Commit 97c7ed4

Browse files
committed
feat: integrate ml-dsa65 support in subscription template services
- Added support for ml-dsa65 public key generation and verification in the subscription template services. - Updated relevant interfaces and methods to accommodate the new mldsa65Verify field. - Bumped version to 2.1.65 in the contract library.
1 parent 4e6d6de commit 97c7ed4

File tree

10 files changed

+107
-3
lines changed

10 files changed

+107
-3
lines changed

libs/contract/commands/subscriptions/get-by/get-raw-subscription-by-short-uuid.command.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export namespace GetRawSubscriptionByShortUuidCommand {
7979
allowInsecure: z.optional(z.nullable(z.boolean())),
8080
shuffleHost: z.optional(z.nullable(z.boolean())),
8181
mihomoX25519: z.optional(z.nullable(z.boolean())),
82+
mldsa65Verify: z.optional(z.nullable(z.string())),
8283
protocolOptions: z.optional(
8384
z.nullable(
8485
z.object({

libs/contract/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@remnawave/backend-contract",
3-
"version": "2.1.64",
3+
"version": "2.1.65",
44
"public": true,
55
"license": "AGPL-3.0-only",
66
"description": "A contract library for Remnawave Backend. It can be used in backend and frontend.",

package-lock.json

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"@nestjs/swagger": "11.2.0",
7272
"@nestjs/terminus": "^11.0.0",
7373
"@nestjstools/messaging": "^2.22.0",
74+
"@noble/post-quantum": "^0.5.2",
7475
"@peculiar/webcrypto": "^1.5.0",
7576
"@peculiar/x509": "^1.14.0",
7677
"@prisma/adapter-pg": "^6.15.0",
@@ -163,4 +164,4 @@
163164
"typescript": "~5.9.2",
164165
"typescript-eslint": "^8.39.1"
165166
}
166-
}
167+
}

src/common/helpers/xray-config/resolve-public-key.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createPrivateKey, createPublicKey, KeyObject } from 'node:crypto';
2+
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
23

34
export async function resolveInboundAndPublicKey(inbounds: any[]): Promise<Map<string, string>> {
45
const publicKeyMap = new Map<string, string>();
@@ -36,6 +37,36 @@ export async function resolveInboundAndPublicKey(inbounds: any[]): Promise<Map<s
3637
return publicKeyMap;
3738
}
3839

40+
export async function resolveInboundAndMlDsa65PublicKey(
41+
inbounds: any[],
42+
): Promise<Map<string, string>> {
43+
const mldsa65PublicKeyMap = new Map<string, string>();
44+
45+
for (const inbound of inbounds) {
46+
if (inbound.streamSettings?.realitySettings?.mldsa65Seed) {
47+
try {
48+
if (mldsa65PublicKeyMap.has(inbound.tag)) {
49+
continue;
50+
}
51+
52+
const publicKey = getMlDsa65PublicKey(
53+
inbound.streamSettings.realitySettings.mldsa65Seed,
54+
);
55+
56+
if (!publicKey) {
57+
continue;
58+
}
59+
60+
mldsa65PublicKeyMap.set(inbound.tag, publicKey);
61+
} catch {
62+
continue;
63+
}
64+
}
65+
}
66+
67+
return mldsa65PublicKeyMap;
68+
}
69+
3970
async function createX25519KeyPairFromBase64(base64PrivateKey: string): Promise<{
4071
publicKey: KeyObject;
4172
privateKey: KeyObject;
@@ -64,3 +95,13 @@ async function createX25519KeyPairFromBase64(base64PrivateKey: string): Promise<
6495
}
6596
});
6697
}
98+
99+
export function getMlDsa65PublicKey(seed: string): string | null {
100+
try {
101+
const seedBuffer = Buffer.from(seed, 'base64');
102+
const { publicKey } = ml_dsa65.keygen(seedBuffer);
103+
return Buffer.from(publicKey).toString('base64url');
104+
} catch {
105+
return null;
106+
}
107+
}

src/modules/subscription-template/generators/format-hosts.service.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ import {
1313
WebSocketObject,
1414
xHttpObject,
1515
} from '@common/helpers/xray-config/interfaces/transport.config';
16+
import {
17+
resolveInboundAndMlDsa65PublicKey,
18+
resolveInboundAndPublicKey,
19+
} from '@common/helpers/xray-config';
1620
import { RawObject } from '@common/helpers/xray-config/interfaces/transport.config';
1721
import { TemplateEngine } from '@common/utils/templates/replace-templates-values';
18-
import { resolveInboundAndPublicKey } from '@common/helpers/xray-config';
1922
import { ICommandResponse } from '@common/types/command-response.type';
2023
import { InboundObject } from '@common/helpers/xray-config/interfaces';
2124
import { setVlessRouteForUuid } from '@common/utils/vless-route';
@@ -106,6 +109,9 @@ export class FormatHostsService {
106109
}
107110

108111
const publicKeyMap = await resolveInboundAndPublicKey(hosts.map((host) => host.rawInbound));
112+
const mldsa65PublicKeyMap = await resolveInboundAndMlDsa65PublicKey(
113+
hosts.map((host) => host.rawInbound),
114+
);
109115

110116
const knownRemarks = new Map<string, number>();
111117

@@ -228,6 +234,7 @@ export class FormatHostsService {
228234
let publicKeyFromConfig: string | undefined;
229235
let shortIdFromConfig: string | undefined;
230236
let spiderXFromConfig: string | undefined;
237+
let mldsa65PublicKeyFromConfig: string | undefined;
231238

232239
switch (inbound.streamSettings?.security) {
233240
case 'tls':
@@ -252,6 +259,7 @@ export class FormatHostsService {
252259
fingerprintFromConfig = realitySettings?.fingerprint;
253260

254261
publicKeyFromConfig = publicKeyMap.get(inbound.tag);
262+
mldsa65PublicKeyFromConfig = mldsa65PublicKeyMap.get(inbound.tag);
255263

256264
spiderXFromConfig = realitySettings?.spiderX;
257265
const shortIds = inbound.streamSettings?.realitySettings?.shortIds || [];
@@ -406,6 +414,7 @@ export class FormatHostsService {
406414
shuffleHost: inputHost.shuffleHost,
407415
mihomoX25519: inputHost.mihomoX25519,
408416
dbData,
417+
mldsa65Verify: mldsa65PublicKeyFromConfig,
409418
});
410419
}
411420

src/modules/subscription-template/generators/interfaces/formatted-hosts.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ export interface IFormattedHost {
3535
shuffleHost?: boolean;
3636
mihomoX25519?: boolean;
3737
dbData?: IDbHostData;
38+
mldsa65Verify?: string;
3839
}

src/modules/subscription-template/generators/interfaces/raw-host.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export interface IRawHost {
4646
allowInsecure?: boolean;
4747
shuffleHost?: boolean;
4848
mihomoX25519?: boolean;
49+
mldsa65Verify?: string;
4950
protocolOptions?: {
5051
ss?: {
5152
method: string;

src/modules/subscription-template/generators/xray-json.generator.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@ export class XrayJsonGeneratorService {
345345
settings.publicKey = host.publicKey;
346346
}
347347

348+
if (host.mldsa65Verify) {
349+
settings.mldsa65Verify = host.mldsa65Verify;
350+
}
351+
348352
if (host.shortId) {
349353
settings.shortId = host.shortId;
350354
}

src/modules/subscription-template/generators/xray.generator.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export class XrayGeneratorService {
170170
fp: params.fingerprint,
171171
pbk: params.publicKey,
172172
sid: params.shortId,
173+
pqv: params.mldsa65Verify,
173174
...(params.spiderX && { spx: params.spiderX }),
174175
});
175176
}
@@ -244,6 +245,7 @@ export class XrayGeneratorService {
244245
fp: params.fingerprint,
245246
pbk: params.publicKey,
246247
sid: params.shortId,
248+
pqv: params.mldsa65Verify,
247249
...(params.spiderX && { spx: params.spiderX }),
248250
});
249251
}

0 commit comments

Comments
 (0)