]> git.codecow.com Git - libnemo.git/commitdiff
Update signing of arbitrary data to accept it as a single string instead of a rest...
authorChris Duncan <chris@zoso.dev>
Fri, 1 May 2026 06:26:49 +0000 (23:26 -0700)
committerChris Duncan <chris@zoso.dev>
Fri, 1 May 2026 06:26:49 +0000 (23:26 -0700)
src/lib/ledger.ts
src/lib/rolodex.ts
src/lib/tools.ts
src/lib/wallet/index.ts
src/lib/wallet/sign.ts

index 2e51d7c08e7e3c3223f783bcbc5e7ebd5e20f836..72fd3b672d27bd9c9873da17ef1b205f14689103 100644 (file)
@@ -284,7 +284,7 @@ export class Ledger {
                                throw new Error('Signing with ledger failed', { cause: status })
                        }
                        if (data instanceof Block && hash !== data.hash) {
-                               throw new Error('Hash from ledger does not match hash from block', { cause: `${hash} | ${data.hash}` })
+                               throw new Error('Hash from Ledger does not match hash from block', { cause: `${hash} | ${data.hash}` })
                        }
                        if (signature == null) {
                                throw new Error('Ledger silently failed to return signature')
index 1b8d00a26238043ec3a7167d875e873f8ae23dff..147f630bfc73b2bf417f832c8d1be99072b748f1 100644 (file)
@@ -175,18 +175,18 @@ export class Rolodex {
 
        /**
        * Verifies whether the public key of any Nano address saved under a specific
-       * name in the rolodex was used to sign a specific set of data.
+       * name in the rolodex was used to sign a specific string.
        *
        * @param {string} name - Alias to look up
        * @param {string} signature - Signature to use for verification
-       * @param {...string} data - Signed data to verify
+       * @param {string} data - Signed data to verify
        * @returns {Promise<boolean>} True if the signature was used to sign the data, else false
        */
-       static async verify (name: string, signature: string, ...data: string[]): Promise<boolean> {
+       static async verify (name: string, signature: string, data: string): Promise<boolean> {
                const addresses = await this.getAddresses(name)
                for (const address of addresses) {
                        const { publicKey } = new Account(address)
-                       const verified = await Tools.verify(publicKey, signature, ...data)
+                       const verified = await Tools.verify(publicKey, signature, data)
                        if (verified) {
                                return true
                        }
index dc55b3b6c251935fc73bb521305a345516646a9d..e95f0c59fc09bf1fe0293476dc1a2aaebaceb2ef 100644 (file)
@@ -138,14 +138,14 @@ export class Tools {
        }
 
        /**
-        * Concatenates and signs an arbitrary set of strings with a secret key using
-        * nano25519. The input data can be up to 32 KiB in total.
+        * Signs an arbitrary string with a secret key using nano25519. The input data
+        * is encoded as UTF-8 and can be up to 32 KiB in total.
         *
         * @param {(string | ArrayBuffer | Uint8Array<ArrayBuffer>)} secretKey - 64-byte secret key
-        * @param {...string[]} input - Data to be concatenated and then signed
+        * @param {string} input - Data to be signed
         * @returns {string} 64-byte hexadecimal signature
         */
-       static sign (secretKey: string | ArrayBuffer | Uint8Array<ArrayBuffer>, ...input: string[]): string {
+       static sign (secretKey: string | ArrayBuffer | Uint8Array<ArrayBuffer>, input: string): string {
                if (navigator.userActivation?.isActive === false) {
                        throw new DOMException(
                                'Signing request was blocked due to lack of user activation',
@@ -154,7 +154,7 @@ export class Tools {
                }
                const k = this.#normalize(secretKey)
                try {
-                       const signature = nano25519_sign(utf8.toBytes(input.join('')), k)
+                       const signature = nano25519_sign(utf8.toBytes(input), k)
                        return bytes.toHex(signature)
                } catch (err) {
                        throw new Error(`Failed to sign message`, { cause: err })
@@ -222,18 +222,18 @@ export class Tools {
        }
 
        /**
-        * Verifies the signature of arbitrary strings using a public key.
+        * Verifies the signature of an arbitrary string using a public key.
         *
         * @param {(string | ArrayBuffer | Uint8Array<ArrayBuffer>)} publicKey - 32-byte hexadecimal public key
         * @param {(string | ArrayBuffer | Uint8Array<ArrayBuffer>)} signature - 128-character hexadcimal signature
-        * @param {...string} input - Data to be verified
+        * @param {string} input - Data to be verified
         * @returns {boolean} True if the data was signed by the public key's matching private key
         */
-       static verify (publicKey: string | ArrayBuffer | Uint8Array<ArrayBuffer>, signature: string | ArrayBuffer | Uint8Array<ArrayBuffer>, ...input: string[]): boolean {
+       static verify (publicKey: string | ArrayBuffer | Uint8Array<ArrayBuffer>, signature: string | ArrayBuffer | Uint8Array<ArrayBuffer>, input: string): boolean {
                const k = this.#normalize(publicKey)
                const s = this.#normalize(signature)
                try {
-                       return nano25519_verify(s, utf8.toBytes(input.join('')), k)
+                       return nano25519_verify(s, utf8.toBytes(input), k)
                } catch (err) {
                        throw new Error('Failed to verify signature', { cause: err })
                }
index ebb999e2a33eb4f00d35690273a449f57b6eef8c..ab4e015b046cec500517279ee7c2c1efad034c95 100644 (file)
@@ -348,10 +348,10 @@ export class Wallet {
        * Plan for this eventuality if you implement this method to sign nonces.\r
        *\r
        * @param {number} index - Account to use for signing\r
-       * @param {(string|string[])} data - Arbitrary data to be signed\r
+       * @param {string} data - Arbitrary data to be signed\r
        * @returns {Promise<string>} 128-character hexadecimal detached signature\r
        */\r
-       async sign (index: number, data: string | string[]): Promise<string>\r
+       async sign (index: number, data: string): Promise<string>\r
        /**\r
        * Signs a block using the private key of the account at the wallet index\r
        * specified. The signature is appended to the signature field of the block,\r
@@ -369,13 +369,15 @@ export class Wallet {
        * is returned to allow chaining with other Block functions. The wallet must be\r
        * unlocked prior to signing.\r
        *\r
+       * See documentation on the class method `Ledger.sign()` for more information.\r
+       *\r
        * @param {number} index - Account to use for signing\r
        * @param {Block} block - Block data to be hashed and signed\r
        * @param {Block} [frontier] - Previous block data to be cached by Ledger wallet\r
        * @returns {Promise<Block>} Block with signature\r
        */\r
        async sign (index: number, block: Block, frontier?: Block): Promise<Block>\r
-       async sign (index: number, data: string | string[] | Block, frontier?: Block): Promise<Block | string> {\r
+       async sign (index: number, data: string | Block, frontier?: Block): Promise<Block | string> {\r
                const { address } = await this.account(index)\r
                return data instanceof Block\r
                        ? _signBlock(this, this.#vault, index, address, data, frontier)\r
index cf5ee23b2f2f83664cea6338b04d4c94f9772d95..9a69cb0fd48ba7185387facbc8ca1a3f8cbdedca 100644 (file)
@@ -51,7 +51,7 @@ export async function _signBlock (wallet: Wallet, vault: Vault, index: unknown,
        }
 }
 
-export async function _signData (wallet: Wallet, vault: Vault, index: number, address: string, data: string | string[]): Promise<string>
+export async function _signData (wallet: Wallet, vault: Vault, index: number, address: string, data: string): Promise<string>
 export async function _signData (wallet: Wallet, vault: Vault, index: unknown, address: unknown, data: unknown): Promise<string> {
        try {
                if (typeof index !== 'number') {
@@ -60,12 +60,11 @@ export async function _signData (wallet: Wallet, vault: Vault, index: unknown, a
                if (typeof address !== 'string') {
                        throw new TypeError('Address must be a string', { cause: address })
                }
-               const message = Array.isArray(data) ? data : [data]
-               if (message.some(s => typeof s !== 'string')) {
-                       throw new TypeError('Data to sign must be strings', { cause: data })
+               if (typeof data !== 'string') {
+                       throw new TypeError('Data to sign must be a string', { cause: data })
                }
                if (wallet.type === 'Ledger') {
-                       return await Ledger.sign(index, message[0])
+                       return Ledger.sign(index, data)
                }
                if (navigator.userActivation?.isActive === false) {
                        throw new DOMException(
@@ -76,7 +75,7 @@ export async function _signData (wallet: Wallet, vault: Vault, index: unknown, a
                const { signature } = await vault.request<ArrayBuffer>({
                        action: 'sign',
                        index,
-                       message: utf8.toBuffer(message.join(''))
+                       message: utf8.toBuffer(data)
                })
                return bytes.toHex(new Uint8Array(signature))
        } catch (err) {