diff --git a/.prettierrc b/.prettierrc index 492a291..c831275 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { - "printWidth": 120, - "tabWidth": 4, - "trailingComma": "all", - "useTabs": true + "printWidth": 120, + "tabWidth": 5, + "trailingComma": "all", + "useTabs": true } diff --git a/.vscode/settings.json b/.vscode/settings.json index 99e79d1..2bed2cd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,22 +1,23 @@ { - // Lune - "luau-lsp.require.mode": "relativeToFile", - "luau-lsp.require.directoryAliases": { - "@lune/": "~/.lune/.typedefs/0.8.2/" - }, + // Lune + "luau-lsp.require.mode": "relativeToFile", + "luau-lsp.require.directoryAliases": { + "@lune/": "~/.lune/.typedefs/0.8.2/" + }, - // Formatting - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "[luau][lua]": { - "editor.defaultFormatter": "JohnnyMorganz.stylua" - }, + // Formatting + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[luau][lua]": { + "editor.defaultFormatter": "JohnnyMorganz.stylua" + }, - // Linting - "eslint.run": "onType", - "eslint.format.enable": true, + // Linting + "eslint.run": "onType", + "eslint.format.enable": true, + "cSpell.enabled": false, - // Misc - "typescript.tsdk": "node_modules/typescript/lib", - "files.eol": "\n" + // Misc + "typescript.tsdk": "node_modules/typescript/lib", + "files.eol": "\n" } diff --git a/package.json b/package.json index afaf36d..c62f5c8 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "build": "rbxtsc", "watch": "rbxtsc -w", "lint": "eslint src", - "fmt": "prettier .", + "check_fmt": "prettier -c src/", + "check": "pnpm lint && pnpm check_fmt", + "fmt": "prettier -w src/", "postinstall": "patch -f node_modules/@rbxts/types/include/roblox.d.ts < lune_require_patch.diff", "prepublishOnly": "pnpm run build" }, diff --git a/src/base64.ts b/src/base64.ts index 67ff5e3..42a9389 100644 --- a/src/base64.ts +++ b/src/base64.ts @@ -1,117 +1,111 @@ const { slice } = require<{ - slice: (arr: T[], start: number, stop?: number) => T[]; + slice: (arr: T[], start: number, stop?: number) => T[]; }>("util"); function stringToBytes(str: string) { - let result = []; + const result = []; - for (let i = 0; i < str.size(); i++) { - result.push(string.byte(str, i + 1)[0]); - } + for (let i = 0; i < str.size(); i++) { + result.push(string.byte(str, i + 1)[0]); + } - return result; + return result; } // Adapted from https://github.com/un-ts/ab64/blob/main/src/ponyfill.ts#L24 const _atob = (asc: string) => { - const b64CharList = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + const b64CharList = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - const b64Chars = string.split(b64CharList, ""); + const b64Chars = string.split(b64CharList, ""); - const b64Table = b64Chars.reduce>( - (acc, char, index) => { - acc[char] = index; - return acc; - }, - {} - ); + const b64Table = b64Chars.reduce>((acc, char, index) => { + acc[char] = index; + return acc; + }, {}); - const fromCharCode = string.char; + const fromCharCode = string.char; - asc = string.gsub(asc, "%s+", "")[0]; - asc += string.char(...slice(stringToBytes("=="), 2 - (asc.size() & 3))); + asc = string.gsub(asc, "%s+", "")[0]; + asc += string.char(...slice(stringToBytes("=="), 2 - (asc.size() & 3))); - let u24: number; - let binary = ""; - let r1: number; - let r2: number; + let u24: number; + let binary = ""; + let r1: number; + let r2: number; - for (let i = 0; i < asc.size(); ) { - u24 = - (b64Table[string.byte(asc, i++)[0]] << 18) | - (b64Table[string.byte(asc, i++)[0]] << 12) | - ((r1 = b64Table[string.byte(asc, i++)[0]]) << 6) | - (r2 = b64Table[string.byte(asc, i++)[0]]); - binary += - r1 === 64 - ? fromCharCode((u24 >> 16) & 255) - : r2 === 64 - ? fromCharCode((u24 >> 16) & 255, (u24 >> 8) & 255) - : fromCharCode((u24 >> 16) & 255, (u24 >> 8) & 255, u24 & 255); - } + for (let i = 0; i < asc.size(); ) { + u24 = + (b64Table[string.byte(asc, i++)[0]] << 18) | + (b64Table[string.byte(asc, i++)[0]] << 12) | + ((r1 = b64Table[string.byte(asc, i++)[0]]) << 6) | + (r2 = b64Table[string.byte(asc, i++)[0]]); + binary += + r1 === 64 + ? fromCharCode((u24 >> 16) & 255) + : r2 === 64 + ? fromCharCode((u24 >> 16) & 255, (u24 >> 8) & 255) + : fromCharCode((u24 >> 16) & 255, (u24 >> 8) & 255, u24 & 255); + } - return binary; + return binary; }; // Adapted from https://gist.github.com/jonleighton/958841 export function atob(buf: number[]): string { - let base64 = ""; - let encodings = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let base64 = ""; + const encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - let byteLength = buf.size(); - let byteRemainder = byteLength % 3; - let mainLength = byteLength - byteRemainder; + const byteLength = buf.size(); + const byteRemainder = byteLength % 3; + const mainLength = byteLength - byteRemainder; - let a: number, b: number, c: number, d: number; - let chunk; + let a: number, b: number, c: number, d: number; + let chunk; - // Main loop deals with bytes in chunks of 3 - for (let i = 0; i < mainLength; i = i + 3) { - // Combine the three bytes into a single integer - chunk = (buf[i] << 16) | (buf[i + 1] << 8) | buf[i + 2]; + // Main loop deals with bytes in chunks of 3 + for (let i = 0; i < mainLength; i = i + 3) { + // Combine the three bytes into a single integer + chunk = (buf[i] << 16) | (buf[i + 1] << 8) | buf[i + 2]; - // Use bitmasks to extract 6-bit segments from the triplet - a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 - b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 - c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 - d = chunk & 63; // 63 = 2^6 - 1 + // Use bitmasks to extract 6-bit segments from the triplet + a = (chunk & 16515072) >> 18; + b = (chunk & 258048) >> 12; + c = (chunk & 4032) >> 6; + d = chunk & 63; - // Convert the raw binary segments to the appropriate ASCII encoding - base64 += - string.char(string.byte(encodings, a + 1)[0]) + - string.char(string.byte(encodings, b + 1)[0]) + - string.char(string.byte(encodings, c + 1)[0]) + - string.char(string.byte(encodings, d + 1)[0]); - } + // Convert the raw binary segments to the appropriate ASCII encoding + base64 += + string.char(string.byte(encodings, a + 1)[0]) + + string.char(string.byte(encodings, b + 1)[0]) + + string.char(string.byte(encodings, c + 1)[0]) + + string.char(string.byte(encodings, d + 1)[0]); + } - // Deal with the remaining bytes and padding - if (byteRemainder === 1) { - chunk = buf[mainLength]; + // Deal with the remaining bytes and padding + if (byteRemainder === 1) { + chunk = buf[mainLength]; - a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 + a = (chunk & 252) >> 2; - // Set the 4 least significant bits to zero - b = (chunk & 3) << 4; // 3 = 2^2 - 1 + // Set the 4 least significant bits to zero + b = (chunk & 3) << 4; - base64 += - string.byte(encodings, a)[0] + string.byte(encodings, b)[0] + "=="; - } else if (byteRemainder === 2) { - chunk = (buf[mainLength] << 8) | buf[mainLength + 1]; + base64 += string.byte(encodings, a)[0] + string.byte(encodings, b)[0] + "=="; + } else if (byteRemainder === 2) { + chunk = (buf[mainLength] << 8) | buf[mainLength + 1]; - a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 - b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 + a = (chunk & 64512) >> 10; + b = (chunk & 1008) >> 4; - // Set the 2 least significant bits to zero - c = (chunk & 15) << 2; // 15 = 2^4 - 1 + // Set the 2 least significant bits to zero + c = (chunk & 15) << 2; - base64 += - string.char(string.byte(encodings, a + 1)[0]) + - string.char(string.byte(encodings, b + 1)[0]) + - string.char(string.byte(encodings, c + 1)[0]) + - "="; - } + base64 += + string.char(string.byte(encodings, a + 1)[0]) + + string.char(string.byte(encodings, b + 1)[0]) + + string.char(string.byte(encodings, c + 1)[0]) + + "="; + } - return base64; + return base64; } diff --git a/src/index.ts b/src/index.ts index 54299de..e4493e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,26 +1,26 @@ const { generatePrivateKey, generatePublicKey } = require<{ - generatePrivateKey: () => number[]; - generatePublicKey: (privateKey: number[]) => number[]; + generatePrivateKey: () => number[]; + generatePublicKey: (privateKey: number[]) => number[]; }>("wg"); const { atob } = require<{ atob: (buf: number[]) => string }>("base64"); export interface Keypair { - publicKey: string; - privateKey: string; + publicKey: string; + privateKey: string; } export interface Wireguard { - generateKeypair(): Keypair; + generateKeypair(): Keypair; } export const wireguard: Wireguard = { - generateKeypair: function () { - const privateKey = generatePrivateKey(); - const publicKey = generatePublicKey(privateKey); + generateKeypair: function () { + const privateKey = generatePrivateKey(); + const publicKey = generatePublicKey(privateKey); - return { - publicKey: atob(publicKey), - privateKey: atob(privateKey), - }; - }, + return { + publicKey: atob(publicKey), + privateKey: atob(privateKey), + }; + }, }; diff --git a/src/util.ts b/src/util.ts index 5907223..88ef4e8 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,21 +1,21 @@ export function slice(arr: T[], start: number, stop?: number): T[] { - const length = arr.size(); + const length = arr.size(); - if (start < 0) { - start = math.max(length + start, 0); - } + if (start < 0) { + start = math.max(length + start, 0); + } - if (stop === undefined) { - stop = length; - } else if (stop < 0) { - stop = math.max(length + stop, 0); - } + if (stop === undefined) { + stop = length; + } else if (stop < 0) { + stop = math.max(length + stop, 0); + } - const result: T[] = []; + const result: T[] = []; - for (let i = start; i < stop; i++) { - result.push(arr[i]); - } + for (let i = start; i < stop; i++) { + result.push(arr[i]); + } - return result; + return result; } diff --git a/src/wg.ts b/src/wg.ts index fa656ff..74c2140 100644 --- a/src/wg.ts +++ b/src/wg.ts @@ -1,282 +1,171 @@ const { atob } = require<{ atob: (buf: number[]) => string }>("base64"); function gf(init?: number[]): number[] { - const r = new Array(16, 0); - if (init) { - for (let i = 0; i < init.size(); ++i) { - r[i] = init[i]; - } - } - return r; + const r = new Array(16, 0); + if (init) { + for (let i = 0; i < init.size(); ++i) { + r[i] = init[i]; + } + } + return r; } function pack(o: number[], n: number[]) { - let b: number, - m = gf(), - t = gf(); - for (let i = 0; i < 16; ++i) { - t[i] = n[i]; - } - carry(t); - carry(t); - carry(t); - for (let j = 0; j < 2; ++j) { - m[0] = t[0] - 0xffed; - for (let i = 1; i < 15; ++i) { - m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); - m[i - 1] &= 0xffff; - } - m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); - b = (m[15] >> 16) & 1; - m[14] &= 0xffff; - cswap(t, m, 1 - b); - } - for (let i = 0; i < 16; ++i) { - o[2 * i] = t[i] & 0xff; - o[2 * i + 1] = t[i] >> 8; - } + let b: number; + const m = gf(), + t = gf(); + for (let i = 0; i < 16; ++i) { + t[i] = n[i]; + } + carry(t); + carry(t); + carry(t); + for (let j = 0; j < 2; ++j) { + m[0] = t[0] - 0xffed; + for (let i = 1; i < 15; ++i) { + m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); + m[i - 1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); + b = (m[15] >> 16) & 1; + m[14] &= 0xffff; + cswap(t, m, 1 - b); + } + for (let i = 0; i < 16; ++i) { + o[2 * i] = t[i] & 0xff; + o[2 * i + 1] = t[i] >> 8; + } } function carry(o: number[]) { - let c: number; - for (let i = 0; i < 16; ++i) { - o[(i + 1) % 16] += (i < 15 ? 1 : 38) * math.floor(o[i] / 65536); - o[i] &= 0xffff; - } + let c: number; + for (let i = 0; i < 16; ++i) { + o[(i + 1) % 16] += (i < 15 ? 1 : 38) * math.floor(o[i] / 65536); + o[i] &= 0xffff; + } } function cswap(p: number[], q: number[], b: number) { - let t: number, - c = ~(b - 1); - for (let i = 0; i < 16; ++i) { - t = c & (p[i] ^ q[i]); - p[i] ^= t; - q[i] ^= t; - } + let t: number; + const c = ~(b - 1); + for (let i = 0; i < 16; ++i) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } } function add(o: number[], a: number[], b: number[]) { - for (let i = 0; i < 16; ++i) { - o[i] = (a[i] + b[i]) | 0; - } + for (let i = 0; i < 16; ++i) { + o[i] = (a[i] + b[i]) | 0; + } } function subtract(o: number[], a: number[], b: number[]) { - for (let i = 0; i < 16; ++i) { - o[i] = (a[i] - b[i]) | 0; - } + for (let i = 0; i < 16; ++i) { + o[i] = (a[i] - b[i]) | 0; + } } function multmod(o: number[], a: number[], b: number[]) { - const t = new Array(31, 0); - for (let i = 0; i < 16; ++i) { - for (let j = 0; j < 16; ++j) { - t[i + j] += a[i] * b[j]; - } - } - for (let i = 0; i < 15; ++i) { - t[i] += 38 * t[i + 16]; - } - for (let i = 0; i < 16; ++i) { - o[i] = t[i]; - } - carry(o); - carry(o); + const t = new Array(31, 0); + for (let i = 0; i < 16; ++i) { + for (let j = 0; j < 16; ++j) { + t[i + j] += a[i] * b[j]; + } + } + for (let i = 0; i < 15; ++i) { + t[i] += 38 * t[i + 16]; + } + for (let i = 0; i < 16; ++i) { + o[i] = t[i]; + } + carry(o); + carry(o); } function invert(o: number[], i: number[]) { - const c = gf(); - for (let a = 0; a < 16; ++a) { - c[a] = i[a]; - } - for (let a = 253; a >= 0; --a) { - multmod(c, c, c); - if (a !== 2 && a !== 4) { - multmod(c, c, i); - } - } - for (let a = 0; a < 16; ++a) { - o[a] = c[a]; - } + const c = gf(); + for (let a = 0; a < 16; ++a) { + c[a] = i[a]; + } + for (let a = 253; a >= 0; --a) { + multmod(c, c, c); + if (a !== 2 && a !== 4) { + multmod(c, c, i); + } + } + for (let a = 0; a < 16; ++a) { + o[a] = c[a]; + } } -let Base64 = { - _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", - encode: function (e: string) { - let t = ""; - let n: number, r: number, i: number, s, o, u, a; - let f = 0; - e = Base64._utf8_encode(e); - while (f < e.size()) { - n = string.byte(e, f++)[0]; - r = string.byte(e, f++)[0]; - i = string.byte(e, f++)[0]; - s = n >> 2; - o = ((n & 3) << 4) | (r >> 4); - u = ((r & 15) << 2) | (i >> 6); - a = i & 63; - if (r !== r) { - u = a = 64; - } else if (i !== i) { - a = 64; - } - t = - t + - string.byte(this._keyStr, s)[0] + - string.byte(this._keyStr, o)[0] + - string.byte(this._keyStr, u)[0] + - string.byte(this._keyStr, a)[0]; - } - return t; - }, - decode: function (e: string) { - let t = ""; - let n, r, i; - let s: number, o: number, u: number, a: number; - let f = 0; - e = string.gsub(e, "[^A-Za-z0-9%+%/%=]", "")[0]; - while (f < e.size()) { - s = string.find( - this._keyStr, - string.char(string.byte(e, f++)[0]) - )[0] as number; - o = string.find( - this._keyStr, - string.char(string.byte(e, f++)[0]) - )[0] as number; - u = string.find( - this._keyStr, - string.char(string.byte(e, f++)[0]) - )[0] as number; - a = string.find( - this._keyStr, - string.char(string.byte(e, f++)[0]) - )[0] as number; - n = (s << 2) | (o >> 4); - r = ((o & 15) << 4) | (u >> 2); - i = ((u & 3) << 6) | a; - t = t + string.char(n); - if (u !== 64) { - t = t + string.char(r); - } - if (a !== 64) { - t = t + string.char(i); - } - } - t = Base64._utf8_decode(t); - return t; - }, - _utf8_encode: function (e: string) { - e = string.gsub(e, "\r\n", "\n")[0]; - let t = ""; - for (let n = 0; n < e.size(); n++) { - let r = string.byte(e, n)[0]; - if (r < 128) { - t += string.char(r); - } else if (r > 127 && r < 2048) { - t += string.char((r >> 6) | 192); - t += string.char((r & 63) | 128); - } else { - t += string.char((r >> 12) | 224); - t += string.char(((r >> 6) & 63) | 128); - t += string.char((r & 63) | 128); - } - } - return t; - }, - _utf8_decode: function (e: string) { - let t = ""; - let n = 0; - let r = 0; - let c1 = 0; - let c2 = 0; - let c3 = 0; - while (n < e.size()) { - r = string.byte(e, n)[0]; - if (r < 128) { - t += string.char(r); - n++; - } else if (r > 191 && r < 224) { - c2 = string.byte(e, n + 1)[0]; - t += string.char(((r & 31) << 6) | (c2 & 63)); - n += 2; - } else { - c2 = string.byte(e, n + 1)[0]; - c3 = string.byte(e, n + 2)[0]; - t += string.char(((r & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - n += 3; - } - } - return t; - }, -}; - function clamp(z: number[]) { - z[31] = (z[31] & 127) | 64; - z[0] &= 248; + z[31] = (z[31] & 127) | 64; + z[0] &= 248; } export function generatePublicKey(privateKey: number[]): number[] { - let r: number, - z = new Array(32, 0); - let a = gf([1]), - b = gf([9]), - c = gf(), - d = gf([1]), - e = gf(), - f = gf(), - _121665 = gf([0xdb41, 1]), - _9 = gf([9]); + let r: number; + const z = new Array(32, 0), + a = gf([1]), + b = gf([9]), + c = gf(), + d = gf([1]), + e = gf(), + f = gf(), + _121665 = gf([0xdb41, 1]), + _9 = gf([9]); - for (let i = 0; i < 32; ++i) { - z[i] = privateKey[i]; - } + for (let i = 0; i < 32; ++i) { + z[i] = privateKey[i]; + } - clamp(z); + clamp(z); - for (let i = 254; i >= 0; --i) { - r = (z[i >>> 3] >>> (i & 7)) & 1; - cswap(a, b, r); - cswap(c, d, r); - add(e, a, c); - subtract(a, a, c); - add(c, b, d); - subtract(b, b, d); - multmod(d, e, e); - multmod(f, a, a); - multmod(a, c, a); - multmod(c, b, e); - add(e, a, c); - subtract(a, a, c); - multmod(b, a, a); - subtract(c, d, f); - multmod(a, c, _121665); - add(a, a, d); - multmod(c, c, a); - multmod(a, d, f); - multmod(d, b, _9); - multmod(b, e, e); - cswap(a, b, r); - cswap(c, d, r); - } + for (let i = 254; i >= 0; --i) { + r = (z[i >>> 3] >>> (i & 7)) & 1; + cswap(a, b, r); + cswap(c, d, r); + add(e, a, c); + subtract(a, a, c); + add(c, b, d); + subtract(b, b, d); + multmod(d, e, e); + multmod(f, a, a); + multmod(a, c, a); + multmod(c, b, e); + add(e, a, c); + subtract(a, a, c); + multmod(b, a, a); + subtract(c, d, f); + multmod(a, c, _121665); + add(a, a, d); + multmod(c, c, a); + multmod(a, d, f); + multmod(d, b, _9); + multmod(b, e, e); + cswap(a, b, r); + cswap(c, d, r); + } - invert(c, c); - multmod(a, a, c); - pack(z, a); + invert(c, c); + multmod(a, a, c); + pack(z, a); - return z; + return z; } function generatePresharedKey(): number[] { - let privateKey = new Array(32, 0).map(() => { - return math.floor(math.random() * 256); - }); + const privateKey = new Array(32, 0).map(() => { + return math.floor(math.random() * 256); + }); - return privateKey; + return privateKey; } export function generatePrivateKey(): number[] { - const privateKey = generatePresharedKey(); - clamp(privateKey); - return privateKey; + const privateKey = generatePresharedKey(); + clamp(privateKey); + return privateKey; }