]> git.codecow.com Git - libnemo.git/commitdiff
Refactor input checking.
authorChris Duncan <chris@zoso.dev>
Sun, 17 Aug 2025 22:17:12 +0000 (15:17 -0700)
committerChris Duncan <chris@zoso.dev>
Sun, 17 Aug 2025 22:17:12 +0000 (15:17 -0700)
src/lib/crypto/nano-nacl.ts

index 104e5af075e4a51b903a54a8a5e6100ae9e8c7f3..a942801e6db714a0b86aed8e89814cfa27a1899a 100644 (file)
@@ -443,25 +443,6 @@ export class NanoNaCl {
                return n\r
        }\r
 \r
-       /**\r
-       * Type-checks arbitrary number of arguments to verify whether they are all\r
-       * Uint8Array<ArrayBuffer> objects.\r
-       *\r
-       * @param {object} args - Key-value pairs of arguments to be checked\r
-       * @throws {TypeError} If any argument is not a Uint8Array<ArrayBuffer>\r
-       */\r
-       static #checkArrayTypes (args: { [i: string]: unknown }): asserts args is { [i: string]: Uint8Array<ArrayBuffer> } {\r
-               for (const arg of Object.keys(args)) {\r
-                       if (typeof args[arg] !== 'object') {\r
-                               throw new TypeError(`Invalid input, expected Uint8Array, actual ${typeof arg}`)\r
-                       }\r
-                       const obj = args[arg] as { [key: string]: unknown }\r
-                       if (!(obj instanceof Uint8Array)) {\r
-                               throw new TypeError(`Invalid input, expected Uint8Array, actual ${obj.constructor?.name ?? typeof arg}`)\r
-                       }\r
-               }\r
-       }\r
-\r
        /**\r
        * Derives a public key from a private key "seed".\r
        *\r
@@ -471,12 +452,14 @@ export class NanoNaCl {
        static convert (seed: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>\r
        static convert (seed: unknown): Uint8Array<ArrayBuffer> {\r
                try {\r
-                       const args: { [i: string]: unknown } = { s: seed }\r
-                       this.#checkArrayTypes(args)\r
-                       const { s } = args\r
-                       if (s.length !== this.crypto_sign_SEEDBYTES) {\r
-                               throw new Error('Invalid seed size to convert to public key')\r
+                       if (!(seed instanceof Uint8Array)) {\r
+                               throw new TypeError('Seed must be Uint8Array')\r
+                       }\r
+                       if (seed.byteLength !== this.crypto_sign_SEEDBYTES) {\r
+                               throw new Error(`Seed must be ${this.crypto_sign_SEEDBYTES} bytes`)\r
                        }\r
+                       const s = new Uint8Array(seed)\r
+                       seed = undefined\r
                        const pk = new Uint8Array(this.crypto_sign_PUBLICKEYBYTES)\r
                        const p: Float64Array[] = [new Float64Array(16), new Float64Array(16), new Float64Array(16), new Float64Array(16)]\r
 \r
@@ -504,15 +487,21 @@ export class NanoNaCl {
        static detached (message: Uint8Array<ArrayBuffer>, privateKey: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>\r
        static detached (message: unknown, privateKey: unknown): Uint8Array<ArrayBuffer> {\r
                try {\r
-                       const args: { [i: string]: unknown } = { msg: message, prv: privateKey }\r
-                       this.#checkArrayTypes(args)\r
-                       const { msg, prv } = args\r
-                       const signed = this.sign(msg, prv)\r
-                       const sig = new Uint8Array(this.crypto_sign_BYTES)\r
-                       for (let i = 0; i < sig.length; i++) {\r
-                               sig[i] = signed[i]\r
+                       if (!(message instanceof Uint8Array)) {\r
+                               throw new TypeError('Message must be Uint8Array')\r
                        }\r
-                       return sig\r
+                       if (!(privateKey instanceof Uint8Array)) {\r
+                               throw new TypeError('Private key must be Uint8Array')\r
+                       }\r
+                       const m = new Uint8Array(message)\r
+                       const mLen = m.length\r
+                       const prv = new Uint8Array(privateKey)\r
+                       message = undefined\r
+                       privateKey = undefined\r
+                       const sm = new Uint8Array(this.crypto_sign_BYTES + mLen)\r
+                       const pub = this.convert(prv)\r
+                       this.crypto_sign(sm, m, mLen, prv, pub)\r
+                       return new Uint8Array(sm.buffer.slice(0, this.crypto_sign_BYTES))\r
                } catch (err) {\r
                        throw new Error('Failed to sign and return signature', { cause: err })\r
                }\r
@@ -528,19 +517,24 @@ export class NanoNaCl {
        static open (signedMessage: Uint8Array<ArrayBuffer>, publicKey: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>\r
        static open (signedMessage: unknown, publicKey: unknown): Uint8Array<ArrayBuffer> {\r
                try {\r
-                       const args: { [i: string]: unknown } = { signed: signedMessage, pub: publicKey }\r
-                       this.#checkArrayTypes(args)\r
-                       const { signed, pub } = args\r
-                       if (pub.byteLength !== this.crypto_sign_PUBLICKEYBYTES) {\r
-                               throw new Error(`Invalid public key size to open message, expected ${this.crypto_sign_PUBLICKEYBYTES}, actual ${pub.byteLength}`)\r
+                       if (!(signedMessage instanceof Uint8Array)) {\r
+                               throw new TypeError('Signed message must be Uint8Array')\r
                        }\r
-                       const tmp = new Uint8Array(signed.length)\r
-                       const mlen = this.crypto_sign_open(tmp, signed, signed.length, pub)\r
-\r
+                       if (!(publicKey instanceof Uint8Array)) {\r
+                               throw new TypeError('Public key must be Uint8Array')\r
+                       }\r
+                       if (publicKey.byteLength !== this.crypto_sign_PUBLICKEYBYTES) {\r
+                               throw new Error(`Public key must be ${this.crypto_sign_PUBLICKEYBYTES} bytes`)\r
+                       }\r
+                       const sm = new Uint8Array(signedMessage)\r
+                       const pub = new Uint8Array(publicKey)\r
+                       signedMessage = undefined\r
+                       publicKey = undefined\r
+                       const tmp = new Uint8Array(sm.length)\r
+                       const mlen = this.crypto_sign_open(tmp, sm, sm.length, pub)\r
                        if (mlen < 0) {\r
                                throw new Error('Signature verification failed')\r
                        }\r
-\r
                        const m = new Uint8Array(mlen)\r
                        m.set(tmp.subarray(0, mlen), 0)\r
                        return m\r
@@ -559,12 +553,19 @@ export class NanoNaCl {
        static sign (message: Uint8Array<ArrayBuffer>, privateKey: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>\r
        static sign (message: unknown, privateKey: unknown): Uint8Array<ArrayBuffer> {\r
                try {\r
-                       const args: { [i: string]: unknown } = { msg: message, prv: privateKey }\r
-                       this.#checkArrayTypes(args)\r
-                       const { msg, prv } = args\r
-                       if (prv.byteLength !== this.crypto_sign_PRIVATEKEYBYTES) {\r
-                               throw new Error(`Invalid key byte length to sign message, expected ${this.crypto_sign_PRIVATEKEYBYTES}, actual ${prv.byteLength}`)\r
+                       if (!(message instanceof Uint8Array)) {\r
+                               throw new TypeError('Message must be Uint8Array')\r
+                       }\r
+                       if (!(privateKey instanceof Uint8Array)) {\r
+                               throw new TypeError('Private key must be Uint8Array')\r
                        }\r
+                       if (privateKey.byteLength !== this.crypto_sign_SEEDBYTES) {\r
+                               throw new Error(`Private key must be ${this.crypto_sign_PRIVATEKEYBYTES} bytes`)\r
+                       }\r
+                       const msg = new Uint8Array(message)\r
+                       const prv = new Uint8Array(privateKey)\r
+                       message = undefined\r
+                       privateKey = undefined\r
                        const signed = new Uint8Array(this.crypto_sign_BYTES + msg.length)\r
                        const pub = this.convert(prv)\r
                        this.crypto_sign(signed, msg, msg.length, prv, pub)\r
@@ -577,23 +578,35 @@ export class NanoNaCl {
        /**\r
        * Verifies a detached signature for a message.\r
        *\r
-       * @param {Uint8Array<ArrayBuffer>} message - Signed message\r
+       * @param {Uint8Array<ArrayBuffer>} signedMessage - Signed message\r
        * @param {Uint8Array<ArrayBuffer>} signature - 64-byte signature\r
        * @param {Uint8Array<ArrayBuffer>} publicKey - 32-byte key used for signing\r
        * @returns {boolean} - True if `publicKey` was used to sign `msg` and generate `sig`, else false\r
        */\r
-       static verify (message: Uint8Array<ArrayBuffer>, signature: Uint8Array<ArrayBuffer>, publicKey: Uint8Array<ArrayBuffer>): boolean\r
-       static verify (message: unknown, signature: unknown, publicKey: unknown): boolean {\r
+       static verify (signedMessage: Uint8Array<ArrayBuffer>, signature: Uint8Array<ArrayBuffer>, publicKey: Uint8Array<ArrayBuffer>): boolean\r
+       static verify (signedMessage: unknown, signature: unknown, publicKey: unknown): boolean {\r
                try {\r
-                       const args: { [i: string]: unknown } = { msg: message, sig: signature, pub: publicKey }\r
-                       this.#checkArrayTypes(args)\r
-                       const { msg, sig, pub } = args\r
-                       if (sig.length !== this.crypto_sign_BYTES) {\r
-                               throw new Error('Invalid signature size to verify signature')\r
+                       if (!(signedMessage instanceof Uint8Array)) {\r
+                               throw new TypeError('Message must be Uint8Array')\r
+                       }\r
+                       if (!(signature instanceof Uint8Array)) {\r
+                               throw new TypeError('Signature must be Uint8Array')\r
+                       }\r
+                       if (!(publicKey instanceof Uint8Array)) {\r
+                               throw new TypeError('Public key must be Uint8Array')\r
+                       }\r
+                       if (signature.byteLength !== this.crypto_sign_BYTES) {\r
+                               throw new Error(`Signature must be ${this.crypto_sign_BYTES} bytes`)\r
                        }\r
-                       if (pub.length !== this.crypto_sign_PUBLICKEYBYTES) {\r
-                               throw new Error('Invalid public key size to verify signature')\r
+                       if (publicKey.byteLength !== this.crypto_sign_PUBLICKEYBYTES) {\r
+                               throw new Error(`Public key must be ${this.crypto_sign_PUBLICKEYBYTES} bytes`)\r
                        }\r
+                       const msg = new Uint8Array(signedMessage)\r
+                       const sig = new Uint8Array(signature)\r
+                       const pub = new Uint8Array(publicKey)\r
+                       signedMessage = undefined\r
+                       signature = undefined\r
+                       publicKey = undefined\r
                        const sm = new Uint8Array(this.crypto_sign_BYTES + msg.length)\r
                        const m = new Uint8Array(this.crypto_sign_BYTES + msg.length)\r
                        sm.set(sig, 0)\r