From 61fcf6918ddebfca6813329e8c0065c56139f4b2 Mon Sep 17 00:00:00 2001
From: Chris Duncan <chris@zoso.dev>
Date: Tue, 5 Nov 2024 23:08:21 -0800
Subject: [PATCH] Nano spec indicates account derivation should use index in
 unsigned 32-bit big endian format. This is opposite of many processor
 architectures, so add a check for endianness for BLAKE2b wallet accounts.
 Also move function to be in alphabetical order.

---
 src/lib/tools.ts  | 40 ++++++++++++++++++++++++++--------------
 src/lib/wallet.ts |  6 +++++-
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/src/lib/tools.ts b/src/lib/tools.ts
index 797ce03..20065ad 100644
--- a/src/lib/tools.ts
+++ b/src/lib/tools.ts
@@ -11,6 +11,19 @@ import { Rpc } from './rpc.js'
 import { Bip44Wallet, Blake2bWallet, LedgerWallet } from './wallet.js'
 import { SendBlock } from './block.js'
 
+/**
+* Hashes data using BLAKE2b.
+*
+* @param {string|string[]} data - Hexadecimal-formatted data to hash
+* @returns {Promise<Uint8Array>} Array of bytes representing hashed input data
+*/
+export async function blake2b (data: string | string[]): Promise<Uint8Array> {
+	if (!Array.isArray(data)) data = [data]
+	const ctx = blake2bInit(32)
+	data.forEach(str => blake2bUpdate(ctx, hex.toBytes(str)))
+	return blake2bFinal(ctx)
+}
+
 /**
 * Converts a decimal amount from one unit divider to another.
 *
@@ -61,19 +74,6 @@ export async function convert (amount: bigint | string, inputUnit: string, outpu
 	return `${i}${f ? '.' : ''}${f}`
 }
 
-/**
-* Hashes data using BLAKE2b.
-*
-* @param {string|string[]} data - Hexadecimal-formatted data to hash
-* @returns {Promise<Uint8Array>} Array of bytes representing hashed input data
-*/
-export async function blake2b (data: string | string[]): Promise<Uint8Array> {
-	if (!Array.isArray(data)) data = [data]
-	const ctx = blake2bInit(32)
-	data.forEach(str => blake2bUpdate(ctx, hex.toBytes(str)))
-	return blake2bFinal(ctx)
-}
-
 /**
 * Converts one or more strings to hexadecimal and hashes them with BLAKE2b.
 *
@@ -88,6 +88,18 @@ export async function hash (data: string | string[]): Promise<string> {
 	return bytes.toHex(hash)
 }
 
+
+/**
+* Checks the endianness of the current machine.
+*
+* @returns {Promise<boolean>} True if little-endian, else false
+*/
+export async function littleEndian () {
+	const buffer = new ArrayBuffer(2)
+	new DataView(buffer).setUint16(0, 256, true)
+	return new Uint16Array(buffer)[0] === 256
+}
+
 /**
 * Signs arbitrary strings with a private key using the Ed25519 signature scheme.
 *
@@ -175,4 +187,4 @@ export async function verify (key: string, signature: string, ...input: string[]
 		hex.toBytes(signature))
 }
 
-export default { blake2b, convert, hash, sign, sweep, verify }
+export default { blake2b, convert, hash, littleEndian, sign, sweep, verify }
diff --git a/src/lib/wallet.ts b/src/lib/wallet.ts
index 96b65ad..3608804 100644
--- a/src/lib/wallet.ts
+++ b/src/lib/wallet.ts
@@ -539,7 +539,11 @@ export class Blake2bWallet extends Wallet {
 	* @returns {Promise<Account>}
 	*/
 	async ckd (index: number): Promise<Account> {
-		const hash = await Tools.blake2b([this.seed, dec.toHex(index, 4)])
+		const indexBytes = dec.toBytes(index, 4)
+		if (await Tools.littleEndian()) {
+			indexBytes.reverse()
+		}
+		const hash = await Tools.blake2b([this.seed, bytes.toHex(indexBytes)])
 		const key = bytes.toHex(hash)
 		return await Account.fromPrivateKey(key, index)
 	}
-- 
2.34.1