Skip to content

Secret Key to Mnemonic

← Back to Mnemonic Utilities

This example demonstrates how to use secretKeyToMnemonic() to convert a 64-byte Algorand secret key to a 25-word mnemonic. Key concepts:

  • Algorand secret keys are 64 bytes: bytes 0-31 are the seed, bytes 32-63 are the public key
  • secretKeyToMnemonic() extracts the first 32 bytes (seed portion) and converts to mnemonic
  • This produces the same result as calling mnemonicFromSeed() on the seed directly
  • No LocalNet required

From the repository root:

Terminal window
cd examples
npm run example algo25/03-secret-key-to-mnemonic.ts

View source on GitHub

03-secret-key-to-mnemonic.ts
/**
* Example: Secret Key to Mnemonic
*
* This example demonstrates how to use secretKeyToMnemonic() to convert a
* 64-byte Algorand secret key to a 25-word mnemonic.
*
* Key concepts:
* - Algorand secret keys are 64 bytes: bytes 0-31 are the seed, bytes 32-63 are the public key
* - secretKeyToMnemonic() extracts the first 32 bytes (seed portion) and converts to mnemonic
* - This produces the same result as calling mnemonicFromSeed() on the seed directly
*
* Prerequisites:
* - No LocalNet required
*/
import { mnemonicFromSeed, secretKeyToMnemonic } from '@algorandfoundation/algokit-utils/algo25'
import { formatHex, printHeader, printInfo, printStep, printSuccess } from '../shared/utils.js'
function main() {
printHeader('Secret Key to Mnemonic Example')
// Step 1: Create a 64-byte secret key (simulating what Algorand uses)
printStep(1, 'Create a 64-byte Algorand Secret Key')
// In Algorand, the secret key is 64 bytes:
// - Bytes 0-31: The seed (private key material)
// - Bytes 32-63: The public key (derived from the seed)
const secretKey = new Uint8Array(64)
crypto.getRandomValues(secretKey)
printInfo(`Secret key length: ${secretKey.length} bytes`)
printInfo(`Structure:`)
printInfo(` Bytes 0-31 (seed): ${formatHex(secretKey.slice(0, 32))}`)
printInfo(` Bytes 32-63 (public key): ${formatHex(secretKey.slice(32, 64))}`)
// Step 2: Display the secret key structure
printStep(2, 'Understand the Secret Key Structure')
printInfo('Algorand secret keys are 64 bytes (512 bits):')
printInfo('')
printInfo(' ┌────────────────────────────────┬────────────────────────────────┐')
printInfo(' │ Seed (32 bytes) │ Public Key (32 bytes) │')
printInfo(' │ Bytes 0-31 │ Bytes 32-63 │')
printInfo(' │ (Private key material) │ (Derived from seed) │')
printInfo(' └────────────────────────────────┴────────────────────────────────┘')
printInfo('')
printInfo('The seed is the actual secret; the public key is appended for convenience.')
printInfo('When converting to mnemonic, only the seed portion is needed.')
// Step 3: Convert secret key to mnemonic using secretKeyToMnemonic
printStep(3, 'Convert Secret Key to Mnemonic using secretKeyToMnemonic()')
const mnemonicFromSecretKey = secretKeyToMnemonic(secretKey)
const words = mnemonicFromSecretKey.split(' ')
printInfo(`Mnemonic has ${words.length} words`)
printInfo('Mnemonic words:')
// Display words in rows of 5 for readability
for (let i = 0; i < words.length; i += 5) {
const row = words.slice(i, i + 5)
const numbered = row.map((w, j) => `${(i + j + 1).toString().padStart(2, ' ')}. ${w.padEnd(10)}`).join(' ')
printInfo(` ${numbered}`)
}
// Step 4: Explain what secretKeyToMnemonic does internally
printStep(4, 'What secretKeyToMnemonic() Does Internally')
printInfo('secretKeyToMnemonic(secretKey) performs these steps:')
printInfo(' 1. Extract the seed: secretKey.slice(0, 32)')
printInfo(' 2. Call mnemonicFromSeed(seed) on the extracted 32 bytes')
printInfo(' 3. Return the resulting 25-word mnemonic')
printInfo('')
printInfo('This is equivalent to:')
printInfo(' const seed = secretKey.slice(0, 32)')
printInfo(' const mnemonic = mnemonicFromSeed(seed)')
// Step 5: Compare with calling mnemonicFromSeed directly
printStep(5, 'Compare with mnemonicFromSeed() on First 32 Bytes')
const seed = secretKey.slice(0, 32)
const mnemonicFromSeedDirect = mnemonicFromSeed(seed)
printInfo('Method 1: secretKeyToMnemonic(64-byte secretKey)')
printInfo(` Result: "${mnemonicFromSecretKey.split(' ').slice(0, 5).join(' ')}..."`)
printInfo('')
printInfo('Method 2: mnemonicFromSeed(secretKey.slice(0, 32))')
printInfo(` Result: "${mnemonicFromSeedDirect.split(' ').slice(0, 5).join(' ')}..."`)
const mnemonicsMatch = mnemonicFromSecretKey === mnemonicFromSeedDirect
printInfo('')
printInfo(`Mnemonics identical: ${mnemonicsMatch ? 'Yes' : 'No'}`)
if (mnemonicsMatch) {
printSuccess('Both methods produce identical mnemonics!')
}
// Step 6: Demonstrate that only the seed portion matters
printStep(6, 'Only the Seed Portion Affects the Mnemonic')
// Create a second secret key with the same seed but different "public key" bytes
const secretKey2 = new Uint8Array(64)
secretKey2.set(seed, 0) // Same seed
crypto.getRandomValues(secretKey2.subarray(32)) // Different public key portion
const mnemonic1 = secretKeyToMnemonic(secretKey)
const mnemonic2 = secretKeyToMnemonic(secretKey2)
printInfo('Secret Key 1 (first 8 bytes of public key):')
printInfo(` ${formatHex(secretKey.slice(32, 40))}...`)
printInfo('Secret Key 2 (first 8 bytes of public key):')
printInfo(` ${formatHex(secretKey2.slice(32, 40))}...`)
printInfo('')
printInfo('Same seed, different public key bytes...')
printInfo(`Mnemonic 1: "${mnemonic1.split(' ').slice(0, 3).join(' ')}..."`)
printInfo(`Mnemonic 2: "${mnemonic2.split(' ').slice(0, 3).join(' ')}..."`)
printInfo(`Mnemonics identical: ${mnemonic1 === mnemonic2 ? 'Yes' : 'No'}`)
if (mnemonic1 === mnemonic2) {
printSuccess('The public key portion (bytes 32-63) does not affect the mnemonic.')
}
// Step 7: Use cases for secretKeyToMnemonic
printStep(7, 'When to Use secretKeyToMnemonic()')
printInfo('Use secretKeyToMnemonic() when you have a 64-byte Algorand secret key')
printInfo('and need to convert it to a mnemonic for backup or display.')
printInfo('')
printInfo('Common scenarios:')
printInfo(' - Exporting an account from a wallet')
printInfo(' - Displaying the recovery phrase after key generation')
printInfo(' - Converting keys from ed25519 libraries that output 64-byte keys')
printInfo('')
printInfo('Use mnemonicFromSeed() directly when you only have the 32-byte seed.')
// Step 8: Summary
printStep(8, 'Summary')
printInfo('secretKeyToMnemonic() converts a 64-byte secret key to a 25-word mnemonic:')
printInfo(' - Input: 64-byte Uint8Array (Algorand secret key format)')
printInfo(' - Output: Space-separated string of 25 words')
printInfo(' - Internally extracts bytes 0-31 (the seed portion)')
printInfo(' - Produces identical result to mnemonicFromSeed(seed)')
printInfo(' - Bytes 32-63 (public key portion) are ignored')
printInfo('')
printInfo('Relationship between functions:')
printInfo(' secretKeyToMnemonic(sk) === mnemonicFromSeed(sk.slice(0, 32))')
printSuccess('Secret Key to Mnemonic example completed successfully!')
}
main()