IronFish Ledger Recovery Key
Reproducing Ledger-compatible Iron Fish keys for Node App import
The Problem
Iron Fish Ledger accounts are derived through a Ledger-style seed derivation flow.
The Ledger recovery phrase is first used as a BIP39 seed source. From there, Ledger applies a derivation path, such as:
m/44'/1338'/0The derived private material is then used to produce the Iron Fish spendingKey, and all other account fields are derived from that key.
Iron Fish Node App mnemonic import works differently. In that flow, the mnemonic is treated as an encoding of an already-formed Iron Fish spendingKey, rather than as a BIP39 seed that should go through Ledger’s derivation path. The technical specification defines this as the exact divergence point between the two flows.
As a result, the same words can lead to different spendingKey values. Once the spendingKey is different, the rest of the account material is different too: viewKey, incomingViewKey, outgoingViewKey, and publicAddress.
Where the Flows Diverge
The Ledger-compatible flow is:
mnemonic
→ BIP39 seed
→ Bip32KholawEd25519 derivation
→ m/44'/1338'/0
→ first 32 bytes of derived private material
→ spendingKey
→ Iron Fish account keys
→ publicAddressThe Node App mnemonic import flow is closer to:
mnemonic
→ Iron Fish mnemonic decoder
→ spendingKey
→ Iron Fish account keys
→ publicAddressThe important difference is not at the address level. It happens earlier, at the point where the spendingKey is created.
This is why importing the same words directly into Node App may not recover the same Ledger account.
What This Tool Does
IronFish Ledger Recovery Key is a standalone utility that reproduces Ledger-derived Iron Fish account material from a Ledger BIP39 seed phrase and derivation path. It then generates an Encoded Key that can be imported into Iron Fish Node App.
The tool supports two main starting points:
- Derive from a Ledger mnemonic.
- Derive from an existing
spendingKey.
From there, it produces the Iron Fish account fields needed for compatibility:
spendingKeyauthorizingKeyproofAuthorizingKeynullifierDerivingKeyviewKeyincomingViewKeyoutgoingViewKeypublicAddress- optional Node App
Encoded Key
The goal is to reproduce the same Ledger-compatible account material and package it in a format that Node App can import.
Technical Flow
1. Ledger-Compatible Derivation
The mnemonic is first converted into a BIP39 seed.
Then the tool applies the Ledger derivation path:
m/44'/1338'/0using Bip32KholawEd25519.
The first 32 bytes of the derived private key material become the Iron Fish spendingKey. The specification also treats 44'/1338'/0 and m/44'/1338'/0 as equivalent normalized paths.
This step is the main compatibility point. If this step is not reproduced, the resulting account may not match Ledger.
2. Spending Key Expansion
After the Ledger-compatible spendingKey has been produced, the process leaves the Ledger-specific part of the flow and enters the standard Iron Fish account derivation flow.
This is the point where compatibility becomes deterministic. The spendingKey is the root secret of the Iron Fish account: if it matches the Ledger-derived value, the remaining account fields can be reproduced from it. If it does not match, the account will diverge from Ledger even if the original mnemonic phrase is the same.
Iron Fish does not use the raw spendingKey directly for every account operation. Instead, it expands the spendingKey into separate pieces of key material. Each piece has its own role in the account model.
The expansion uses BLAKE2b with the Iron Fish personalization string Iron Fish Money :
From the same spendingKey, three values are derived:
ask = ReduceFr(blake2b64(spendingKey || 0x00))
nsk = ReduceFr(blake2b64(spendingKey || 0x01))
ovk = first32(blake2b64(spendingKey || 0x02))The appended byte acts as a domain separator:
0x00derives the authorizing secret key material;0x01derives the proof authorizing key material;0x02derives the outgoing viewing key.
This avoids reusing the same raw secret for different cryptographic purposes. Spending authorization, proof generation, and outgoing viewing are all derived from the same root, but they are separated into distinct deterministic branches.
Next, the tool derives compressed key components from the scalar values:
ak = Compress(ask * SPENDING_KEY_GENERATOR)
nk = Compress(nsk * PROOF_GENERATION_KEY_GENERATOR)The resulting ak and nk are combined into the account viewKey = ak || nk.
From here, the flow can continue to the incoming view key and public address derivation.
This is why the spendingKey is the critical bridge between Ledger and Iron Fish Node App. Once the same spendingKey is reproduced, the rest of the account is no longer ambiguous.
Encoded Key Construction
The practical output of the tool is the Node App importable Encoded Key.
The format is:
ifaccount + base64(JSON)The JSON payload includes the account fields expected by Iron Fish Node App:
{
"name": "ledger-account",
"spendingKey": "...",
"viewKey": "...",
"incomingViewKey": "...",
"outgoingViewKey": "...",
"publicAddress": "...",
"proofAuthorizingKey": "...",
"createdAt": null,
"ledger": false
}The technical specification requires lowercase hex fields for compatibility with Iron Fish validators and comparisons.
This gives users a safer compatibility path:
Ledger mnemonic
→ Ledger-compatible derivation
→ Iron Fish account material
→ Encoded Key
→ Node App importInstead of:
Ledger mnemonic
→ direct Node App mnemonic import
→ potentially different accountValidation
Because this tool handles account recovery material, deterministic behavior is important.
The project includes validation for:
- reference test vectors;
Encoded Keyround-trip decoding;- equivalence between
m/44'/1338'/0and44'/1338'/0; - deterministic derivation from both mnemonic and
spendingKey.
Security Notes
This tool handles sensitive account material.
A few practical rules should be followed:
- run the tool only in a trusted local environment;
- avoid online environments when possible;
- never publish or share seed phrases;
- never publish or share
spendingKey; - do not send seed phrases or private material to external APIs;
- avoid storing plaintext seed phrases in logs or shell history.
The project does not handle transaction signing, hardware transport, APDU communication, or seed storage UX. Its scope is limited to deterministic derivation and Node App import format generation.
Conclusion
This project solves a specific compatibility issue between Ledger-derived Iron Fish accounts and Iron Fish Node App import behavior.
The issue is not that the recovery phrase is invalid. The issue is that the same phrase can be interpreted through different derivation flows.
For Ledger parity, direct mnemonic import is not enough.
To recover the same Ledger account in Iron Fish Node App, we need to reproduce the Ledger derivation flow, not just import the mnemonic.