Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/ripple-keypairs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ function deriveAddress(publicKey: string): string {
return deriveAddressFromBytes(hexToBytes(publicKey))
}

function derivePublicKey(privateKey: string): string {
const algorithm = getAlgorithmFromPrivateKey(privateKey)

if (algorithm === 'ecdsa-secp256k1') {
return secp256k1.deriveKeypairFromPrivateKey(privateKey).publicKey
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (algorithm === 'ed25519') {
return ed25519.deriveKeypairFromPrivateKey(privateKey).publicKey
}
throw new Error('Unknown signing scheme algorithm')
}

function deriveNodeAddress(publicKey: string): string {
const generatorBytes = decodeNodePublic(publicKey)
const accountPublicBytes = accountPublicFromPublicGenerator(generatorBytes)
Expand All @@ -107,6 +120,7 @@ export {
sign,
verify,
deriveAddress,
derivePublicKey,
deriveNodeAddress,
decodeSeed,
}
21 changes: 21 additions & 0 deletions packages/ripple-keypairs/src/signing-schemes/ed25519/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,27 @@ const ed25519: SigningScheme = {
return { privateKey, publicKey }
},

deriveKeypairFromPrivateKey(privateKey: string): {
privateKey: string
publicKey: string
} {
assert.ok(
privateKey.startsWith(ED_PREFIX)
? privateKey.length === 66
: privateKey.length === 64,
'Invalid ed25519 private key length',
)

const normalizedPrivateKey = privateKey.startsWith(ED_PREFIX)
? privateKey.slice(2)
: privateKey

const buffer = Buffer.from(normalizedPrivateKey, 'hex')

const publicKey = ED_PREFIX + bytesToHex(nobleEd25519.getPublicKey(buffer))
return { privateKey, publicKey }
},

Comment on lines +22 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Require ED prefix and avoid Buffer for isomorphic support

  • ed25519 keys must carry the ED prefix across this codebase (sign() enforces length 66). Accepting raw 64-hex here is inconsistent and creates ambiguity with secp256k1 detection.
  • Replace Buffer usage with hexToBytes for browser compatibility.
  • Add strict hex validation.

Apply this diff within the selected range:

   deriveKeypairFromPrivateKey(privateKey: string): {
     privateKey: string
     publicKey: string
   } {
-    assert.ok(
-      privateKey.startsWith(ED_PREFIX)
-        ? privateKey.length === 66
-        : privateKey.length === 64,
-      'Invalid ed25519 private key length',
-    )
-
-    const normalizedPrivateKey = privateKey.startsWith(ED_PREFIX)
-      ? privateKey.slice(2)
-      : privateKey
-
-    const buffer = Buffer.from(normalizedPrivateKey, 'hex')
-
-    const publicKey = ED_PREFIX + bytesToHex(nobleEd25519.getPublicKey(buffer))
-    return { privateKey, publicKey }
+    assert.ok(
+      privateKey.startsWith(ED_PREFIX) && privateKey.length === 66,
+      'ed25519 private key must be 33 bytes including "ED" prefix',
+    )
+    const normalizedPrivateKey = privateKey.slice(2)
+    assert.ok(
+      /^[0-9a-fA-F]{64}$/.test(normalizedPrivateKey),
+      'private key must be 32-byte hex',
+    )
+    const privBytes = hexToBytes(normalizedPrivateKey)
+    const publicKey =
+      ED_PREFIX + bytesToHex(nobleEd25519.getPublicKey(privBytes))
+    return { privateKey, publicKey }
   },

And update the import (outside this hunk):

// change this:
import { bytesToHex } from '@xrplf/isomorphic/utils'
// to this:
import { bytesToHex, hexToBytes } from '@xrplf/isomorphic/utils'
🤖 Prompt for AI Agents
In packages/ripple-keypairs/src/signing-schemes/ed25519/index.ts around lines 22
to 42, enforce that private keys must include the ED_PREFIX (no accepting 64-hex
raw keys), validate the hex string strictly (only [0-9a-fA-F] and exact length
after prefix), convert the normalized hex to bytes using hexToBytes instead of
Buffer for isomorphic/browser support, and return the publicKey prefixed with
ED_PREFIX; also update the module import (outside this hunk) to import
hexToBytes along with bytesToHex as requested.

sign(message: Uint8Array, privateKey: HexString): string {
assert.ok(message instanceof Uint8Array, 'message must be array of octets')
assert.ok(
Expand Down
20 changes: 20 additions & 0 deletions packages/ripple-keypairs/src/signing-schemes/secp256k1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,26 @@ const secp256k1: SigningScheme = {
return { privateKey, publicKey }
},

deriveKeypairFromPrivateKey(privateKey: string): {
privateKey: string
publicKey: string
} {
assert.ok(
(privateKey.length === 66 && privateKey.startsWith(SECP256K1_PREFIX)) ||
privateKey.length === 64,
'Invalid private key length or format',
)
const normalizedPrivateKey =
privateKey.length === 66 && privateKey.startsWith(SECP256K1_PREFIX)
? privateKey.slice(2)
: privateKey

const buffer = Buffer.from(normalizedPrivateKey, 'hex')

const publicKey = bytesToHex(nobleSecp256k1.getPublicKey(buffer, true))
return { privateKey, publicKey }
},

Comment on lines +33 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid Node.js Buffer; use isomorphic hexToBytes and validate hex

Using Buffer breaks browser environments. This package is isomorphic; prefer hexToBytes. Also add a strict hex check to fail fast on malformed input.

Apply this diff within the selected range:

   } {
     assert.ok(
       (privateKey.length === 66 && privateKey.startsWith(SECP256K1_PREFIX)) ||
         privateKey.length === 64,
       'Invalid private key length or format',
     )
-    const normalizedPrivateKey =
+    const normalizedPrivateKey =
       privateKey.length === 66 && privateKey.startsWith(SECP256K1_PREFIX)
         ? privateKey.slice(2)
         : privateKey
-
-    const buffer = Buffer.from(normalizedPrivateKey, 'hex')
-
-    const publicKey = bytesToHex(nobleSecp256k1.getPublicKey(buffer, true))
+    assert.ok(
+      /^[0-9a-fA-F]{64}$/.test(normalizedPrivateKey),
+      'private key must be 32-byte hex',
+    )
+    const privBytes = hexToBytes(normalizedPrivateKey)
+    const publicKey = bytesToHex(nobleSecp256k1.getPublicKey(privBytes, true))
     return { privateKey, publicKey }
   },

And update the import (outside this hunk):

// change this:
import { bytesToHex } from '@xrplf/isomorphic/utils'
// to this:
import { bytesToHex, hexToBytes } from '@xrplf/isomorphic/utils'
🤖 Prompt for AI Agents
In packages/ripple-keypairs/src/signing-schemes/secp256k1/index.ts around lines
33 to 52, the code uses Node's Buffer to decode a hex private key and lacks
strict hex validation; replace Buffer.from(...) with the isomorphic
hexToBytes(privateHex) function (and update the import to include hexToBytes),
and add a strict hex format check (e.g., /^[0-9a-fA-F]+$/ with expected length
64) to fail fast on malformed input before converting and deriving the public
key.

sign(message: Uint8Array, privateKey: HexString): string {
// Some callers pass the privateKey with the prefix, others without.
// @noble/curves will throw if the key is not exactly 32 bytes, so we
Expand Down
2 changes: 2 additions & 0 deletions packages/ripple-keypairs/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface SigningScheme {
options?: DeriveKeyPairOptions,
) => KeyPair

deriveKeypairFromPrivateKey: (privateKey: HexString) => KeyPair

sign: (
// deriveKeyPair creates a Sha512.half as Uint8Array so that's why it takes this
// though it /COULD/ take HexString as well
Expand Down
16 changes: 16 additions & 0 deletions packages/xrpl/src/Wallet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import {
deriveAddress,
deriveKeypair,
derivePublicKey,
generateSeed,
sign,
} from 'ripple-keypairs'
Expand Down Expand Up @@ -173,6 +174,21 @@ export class Wallet {
})
}

/**
* Derives a wallet from a private key.
*
* @param privateKey - A string used to generate a keypair (publicKey/privateKey) to derive a wallet.
* @returns A Wallet derived from a private key.
*
* @throws ValidationError if private key is not a valid string
*/
public static fromPrivateKey(privateKey: string): Wallet {
if (!privateKey || typeof privateKey !== 'string') {
throw new ValidationError('privateKey must be a non-empty string')
}
return new Wallet(derivePublicKey(privateKey), privateKey)
}

Comment on lines +177 to +191
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden validation and normalize error surface

  • Ambiguous input: ed25519 requires an ED-prefixed private key for downstream APIs. Accepting raw 64-hex for ed25519 leads to mis-detection as secp256k1 and subtle bugs. At minimum, make the error explicit.
  • Wrap ripple-keypairs errors in ValidationError to present a consistent API surface.

Apply this diff:

   public static fromPrivateKey(privateKey: string): Wallet {
-    if (!privateKey || typeof privateKey !== 'string') {
-      throw new ValidationError('privateKey must be a non-empty string')
-    }
-    return new Wallet(derivePublicKey(privateKey), privateKey)
+    if (typeof privateKey !== 'string' || privateKey.length === 0) {
+      throw new ValidationError('privateKey must be a non-empty string')
+    }
+    try {
+      const publicKey = derivePublicKey(privateKey)
+      return new Wallet(publicKey, privateKey)
+    } catch (e) {
+      // Note: ed25519 private keys must be 'ED' prefixed (66 hex chars).
+      // secp256k1 private keys may be '00' prefixed (66 hex chars) or raw 64-hex.
+      throw new ValidationError(
+        `Invalid or unsupported privateKey format${
+          e instanceof Error ? `: ${e.message}` : ''
+        }`,
+      )
+    }
   }

Also update the JSDoc to note prefix requirements for each algorithm.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Derives a wallet from a private key.
*
* @param privateKey - A string used to generate a keypair (publicKey/privateKey) to derive a wallet.
* @returns A Wallet derived from a private key.
*
* @throws ValidationError if private key is not a valid string
*/
public static fromPrivateKey(privateKey: string): Wallet {
if (!privateKey || typeof privateKey !== 'string') {
throw new ValidationError('privateKey must be a non-empty string')
}
return new Wallet(derivePublicKey(privateKey), privateKey)
}
/**
* Derives a wallet from a private key.
*
* @param privateKey - A string used to generate a keypair (publicKey/privateKey) to derive a wallet.
* @returns A Wallet derived from a private key.
*
* @throws ValidationError if private key is not a valid string
*/
public static fromPrivateKey(privateKey: string): Wallet {
if (typeof privateKey !== 'string' || privateKey.length === 0) {
throw new ValidationError('privateKey must be a non-empty string')
}
try {
const publicKey = derivePublicKey(privateKey)
return new Wallet(publicKey, privateKey)
} catch (e) {
// Note: ed25519 private keys must be 'ED' prefixed (66 hex chars).
// secp256k1 private keys may be '00' prefixed (66 hex chars) or raw 64-hex.
throw new ValidationError(
`Invalid or unsupported privateKey format${
e instanceof Error ? `: ${e.message}` : ''
}`,
)
}
}
🤖 Prompt for AI Agents
In packages/xrpl/src/Wallet/index.ts around lines 177 to 191, the fromPrivateKey
method currently accepts ambiguous inputs and can mis-detect ed25519 keys;
update validation to require and validate algorithm-specific formats (e.g.
require ED-prefixed private keys for ed25519 and explicit, validated hex format
for secp256k1), throw a ValidationError with an explicit message when the
prefix/format is wrong, and wrap any underlying ripple-keypairs errors in a
ValidationError so the API surface is consistent; also update the JSDoc to
document the prefix/format requirements for each algorithm.

/**
* Derives a wallet from a secret (AKA a seed).
*
Expand Down
45 changes: 45 additions & 0 deletions packages/xrpl/test/wallet/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,51 @@ describe('Wallet', function () {
})
})

describe('from PrivateKey', function () {
describe('using secp256k1 private key', function () {
const mockWallet_secp256k1 = {
address: 'rhvh5SrgBL5V8oeV9EpDuVszeJSSCEkbPc',
publicKey:
'030E58CDD076E798C84755590AAF6237CA8FAE821070A59F648B517A30DC6F589D',
privateKey:
'00141BA006D3363D2FB2785E8DF4E44D3A49908780CB4FB51F6D217C08C021429F',
}

it('derive keypair from private key', function () {
const wallet = Wallet.fromPrivateKey(mockWallet_secp256k1.privateKey)
assert.equal(wallet.address, mockWallet_secp256k1.address)
assert.equal(wallet.publicKey, mockWallet_secp256k1.publicKey)
})

it('throws error for malformed secp256k1 private key', function () {
assert.throws(() =>
Wallet.fromPrivateKey(mockWallet_secp256k1.privateKey.slice(0, 10)),
)
})
})

describe('using ed25519 private key', function () {
const mockWallet_ed25519 = {
address: 'rszPLM97iS8mFTndKQNexGhY1N9ionLVAx',
publicKey:
'EDFD5C3E305FDEB97A89FC39ED333A710A7ED35E3471443C4989F9E3B8F023488D',
privateKey:
'EDDA8694C151CE30E8A2C91884E26BC11A75514E3A27EE6CE4615FABA3DCBE1429',
}
it('derive keypair from private key', function () {
const wallet = Wallet.fromPrivateKey(mockWallet_ed25519.privateKey)
assert.equal(wallet.address, mockWallet_ed25519.address)
assert.equal(wallet.publicKey, mockWallet_ed25519.publicKey)
})

it('throws error for malformed ed25519 private key', function () {
assert.throws(() =>
Wallet.fromPrivateKey(mockWallet_ed25519.privateKey.slice(0, 10)),
)
})
})
})

Comment on lines +440 to +484
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden fromPrivateKey tests: fix suite name, improve consistency, and extend coverage for accepted inputs and invalid cases

Great addition; this validates the new API across both curves. A few improvements will make this suite more robust and consistent with the rest of the file:

  • Consistency/naming: use fromPrivateKey (no space) to match method name; use camelCase for mock constants; align test titles with “derives a wallet…” phrasing used elsewhere.
  • Assertions: also assert privateKey is preserved, classicAddress equals address, and seed is undefined when constructed from a privateKey.
  • Coverage: add tests for accepted input forms:
    • secp256k1 64-char hex without the leading "00" prefix
    • ed25519 without the "ED" prefix
  • Negative cases: add tests for empty string and non-hex input.

Apply this diff within this block:

-  describe('from PrivateKey', function () {
+  describe('fromPrivateKey', function () {
     describe('using secp256k1 private key', function () {
-      const mockWallet_secp256k1 = {
+      const mockWalletSecp256k1 = {
         address: 'rhvh5SrgBL5V8oeV9EpDuVszeJSSCEkbPc',
         publicKey:
           '030E58CDD076E798C84755590AAF6237CA8FAE821070A59F648B517A30DC6F589D',
         privateKey:
           '00141BA006D3363D2FB2785E8DF4E44D3A49908780CB4FB51F6D217C08C021429F',
       }
 
-      it('derive keypair from private key', function () {
-        const wallet = Wallet.fromPrivateKey(mockWallet_secp256k1.privateKey)
-        assert.equal(wallet.address, mockWallet_secp256k1.address)
-        assert.equal(wallet.publicKey, mockWallet_secp256k1.publicKey)
+      it('derives a wallet from private key', function () {
+        const wallet = Wallet.fromPrivateKey(mockWalletSecp256k1.privateKey)
+        assert.equal(wallet.address, mockWalletSecp256k1.address)
+        assert.equal(wallet.publicKey, mockWalletSecp256k1.publicKey)
+        assert.equal(wallet.privateKey, mockWalletSecp256k1.privateKey)
+        assert.equal(wallet.classicAddress, wallet.address)
+        assert.isUndefined((wallet as unknown as { seed?: string }).seed)
       })
 
+      it('accepts 64-char secp256k1 private key without 00 prefix', function () {
+        const unprefixed = mockWalletSecp256k1.privateKey.slice(2)
+        const wallet = Wallet.fromPrivateKey(unprefixed)
+        assert.equal(wallet.address, mockWalletSecp256k1.address)
+        assert.equal(wallet.publicKey, mockWalletSecp256k1.publicKey)
+      })
+
       it('throws error for malformed secp256k1 private key', function () {
         assert.throws(() =>
-          Wallet.fromPrivateKey(mockWallet_secp256k1.privateKey.slice(0, 10)),
+          Wallet.fromPrivateKey(mockWalletSecp256k1.privateKey.slice(0, 10)),
         )
       })
     })
 
     describe('using ed25519 private key', function () {
-      const mockWallet_ed25519 = {
+      const mockWalletEd25519 = {
         address: 'rszPLM97iS8mFTndKQNexGhY1N9ionLVAx',
         publicKey:
           'EDFD5C3E305FDEB97A89FC39ED333A710A7ED35E3471443C4989F9E3B8F023488D',
         privateKey:
           'EDDA8694C151CE30E8A2C91884E26BC11A75514E3A27EE6CE4615FABA3DCBE1429',
       }
-      it('derive keypair from private key', function () {
-        const wallet = Wallet.fromPrivateKey(mockWallet_ed25519.privateKey)
-        assert.equal(wallet.address, mockWallet_ed25519.address)
-        assert.equal(wallet.publicKey, mockWallet_ed25519.publicKey)
+      it('derives a wallet from private key', function () {
+        const wallet = Wallet.fromPrivateKey(mockWalletEd25519.privateKey)
+        assert.equal(wallet.address, mockWalletEd25519.address)
+        assert.equal(wallet.publicKey, mockWalletEd25519.publicKey)
+        assert.equal(wallet.privateKey, mockWalletEd25519.privateKey)
+        assert.equal(wallet.classicAddress, wallet.address)
+        assert.isUndefined((wallet as unknown as { seed?: string }).seed)
       })
 
+      it('accepts ed25519 private key without ED prefix', function () {
+        const unprefixed = mockWalletEd25519.privateKey.slice(2)
+        const wallet = Wallet.fromPrivateKey(unprefixed)
+        assert.equal(wallet.address, mockWalletEd25519.address)
+        assert.equal(wallet.publicKey, mockWalletEd25519.publicKey)
+      })
 
       it('throws error for malformed ed25519 private key', function () {
         assert.throws(() =>
-          Wallet.fromPrivateKey(mockWallet_ed25519.privateKey.slice(0, 10)),
+          Wallet.fromPrivateKey(mockWalletEd25519.privateKey.slice(0, 10)),
         )
       })
     })
+
+    it('throws error for empty private key', function () {
+      assert.throws(() => Wallet.fromPrivateKey(''))
+    })
+
+    it('throws error for non-hex private key', function () {
+      assert.throws(() => Wallet.fromPrivateKey('not-hex'))
+    })
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe('from PrivateKey', function () {
describe('using secp256k1 private key', function () {
const mockWallet_secp256k1 = {
address: 'rhvh5SrgBL5V8oeV9EpDuVszeJSSCEkbPc',
publicKey:
'030E58CDD076E798C84755590AAF6237CA8FAE821070A59F648B517A30DC6F589D',
privateKey:
'00141BA006D3363D2FB2785E8DF4E44D3A49908780CB4FB51F6D217C08C021429F',
}
it('derive keypair from private key', function () {
const wallet = Wallet.fromPrivateKey(mockWallet_secp256k1.privateKey)
assert.equal(wallet.address, mockWallet_secp256k1.address)
assert.equal(wallet.publicKey, mockWallet_secp256k1.publicKey)
})
it('throws error for malformed secp256k1 private key', function () {
assert.throws(() =>
Wallet.fromPrivateKey(mockWallet_secp256k1.privateKey.slice(0, 10)),
)
})
})
describe('using ed25519 private key', function () {
const mockWallet_ed25519 = {
address: 'rszPLM97iS8mFTndKQNexGhY1N9ionLVAx',
publicKey:
'EDFD5C3E305FDEB97A89FC39ED333A710A7ED35E3471443C4989F9E3B8F023488D',
privateKey:
'EDDA8694C151CE30E8A2C91884E26BC11A75514E3A27EE6CE4615FABA3DCBE1429',
}
it('derive keypair from private key', function () {
const wallet = Wallet.fromPrivateKey(mockWallet_ed25519.privateKey)
assert.equal(wallet.address, mockWallet_ed25519.address)
assert.equal(wallet.publicKey, mockWallet_ed25519.publicKey)
})
it('throws error for malformed ed25519 private key', function () {
assert.throws(() =>
Wallet.fromPrivateKey(mockWallet_ed25519.privateKey.slice(0, 10)),
)
})
})
})
describe('fromPrivateKey', function () {
describe('using secp256k1 private key', function () {
const mockWalletSecp256k1 = {
address: 'rhvh5SrgBL5V8oeV9EpDuVszeJSSCEkbPc',
publicKey:
'030E58CDD076E798C84755590AAF6237CA8FAE821070A59F648B517A30DC6F589D',
privateKey:
'00141BA006D3363D2FB2785E8DF4E44D3A49908780CB4FB51F6D217C08C021429F',
}
it('derives a wallet from private key', function () {
const wallet = Wallet.fromPrivateKey(mockWalletSecp256k1.privateKey)
assert.equal(wallet.address, mockWalletSecp256k1.address)
assert.equal(wallet.publicKey, mockWalletSecp256k1.publicKey)
assert.equal(wallet.privateKey, mockWalletSecp256k1.privateKey)
assert.equal(wallet.classicAddress, wallet.address)
assert.isUndefined((wallet as unknown as { seed?: string }).seed)
})
it('accepts 64-char secp256k1 private key without 00 prefix', function () {
const unprefixed = mockWalletSecp256k1.privateKey.slice(2)
const wallet = Wallet.fromPrivateKey(unprefixed)
assert.equal(wallet.address, mockWalletSecp256k1.address)
assert.equal(wallet.publicKey, mockWalletSecp256k1.publicKey)
})
it('throws error for malformed secp256k1 private key', function () {
assert.throws(() =>
Wallet.fromPrivateKey(mockWalletSecp256k1.privateKey.slice(0, 10)),
)
})
})
describe('using ed25519 private key', function () {
const mockWalletEd25519 = {
address: 'rszPLM97iS8mFTndKQNexGhY1N9ionLVAx',
publicKey:
'EDFD5C3E305FDEB97A89FC39ED333A710A7ED35E3471443C4989F9E3B8F023488D',
privateKey:
'EDDA8694C151CE30E8A2C91884E26BC11A75514E3A27EE6CE4615FABA3DCBE1429',
}
it('derives a wallet from private key', function () {
const wallet = Wallet.fromPrivateKey(mockWalletEd25519.privateKey)
assert.equal(wallet.address, mockWalletEd25519.address)
assert.equal(wallet.publicKey, mockWalletEd25519.publicKey)
assert.equal(wallet.privateKey, mockWalletEd25519.privateKey)
assert.equal(wallet.classicAddress, wallet.address)
assert.isUndefined((wallet as unknown as { seed?: string }).seed)
})
it('accepts ed25519 private key without ED prefix', function () {
const unprefixed = mockWalletEd25519.privateKey.slice(2)
const wallet = Wallet.fromPrivateKey(unprefixed)
assert.equal(wallet.address, mockWalletEd25519.address)
assert.equal(wallet.publicKey, mockWalletEd25519.publicKey)
})
it('throws error for malformed ed25519 private key', function () {
assert.throws(() =>
Wallet.fromPrivateKey(mockWalletEd25519.privateKey.slice(0, 10)),
)
})
})
it('throws error for empty private key', function () {
assert.throws(() => Wallet.fromPrivateKey(''))
})
it('throws error for non-hex private key', function () {
assert.throws(() => Wallet.fromPrivateKey('not-hex'))
})
})

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@interc0der The following two test cases are useful additions: accepts ed25519/secp256k1 private key without ED/00 prefix

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

// eslint-disable-next-line max-statements -- Required for test coverage.
describe('sign', function () {
let wallet: Wallet
Expand Down