NIP-06: Basic key derivation from mnemonic seed phrase

In accordance with the BIP-32 and BIP-39 we can derive Nostr keys using seed phrases as a source of entropy.

The default functionality is to generate a single key-pair at the derivation path 0. However, it is also possible to perform more advanced derivations by incrementing the account, enabling the generation of many sets of keys from a single mnemonic seed phrase.

Rust

TODO

Python

Using the from_mnemonic() method in conjunction with the Keys class to derived a basic set of Nostr keys from a 24 word seed phrase.

Note that this example uses the Mnemonic class from the python-mnemonic package (the reference implementation of BIP-39) to randomly generate example seed phrases.

# Generate random Seed Phrase (24 words e.g. 256 bits entropy)
print("Keys from 24 word Seed Phrase:")
words = Mnemonic("english").generate(strength=256)
passphrase = ""

# Use Seed Phrase to generate basic Nostr keys
keys = Keys.from_mnemonic(words, passphrase)

print(f" Seed Words (24)  : {words}")
print(f" Public key bech32: {keys.public_key().to_bech32()}")
print(f" Secret key bech32: {keys.secret_key().to_bech32()}")

As well as deriving basic keys from a 24 word seed we can also use seed phrases of other lengths such as 18 words or, as in this example, 12 words.

# Generate random Seed Phrase (12 words e.g. 128 bits entropy)
print("Keys from 12 word Seed Phrase:")
words = Mnemonic("english").generate(strength=128)
passphrase = ""

# Use Seed Phrase to generate basic Nostr keys
keys = Keys.from_mnemonic(words, passphrase)

print(f" Seed Words (12)  : {words}")
print(f" Public key bech32: {keys.public_key().to_bech32()}")
print(f" Secret key bech32: {keys.secret_key().to_bech32()}")

Advanced key derivation functionality (for accounts) can be accessed by the from_mnemonic() method. To do this we use the account argument which accepts an integer to specify the derivation path.

# Advanced (with accounts) from the example wordlist
words = "leader monkey parrot ring guide accident before fence cannon height naive bean"
passphrase = ""

print("Accounts (0-5) from 12 word Seed Phrase (with passphrase):")
print(f" Seed Words (12): {words}")
print(" Accounts (0-5) :")

# Use Seed Phrase and account to multiple Nostr keys
for account in range(0,6):
    nsec = Keys.from_mnemonic(words, passphrase, account).secret_key().to_bech32()
    print(f"     Account #{account} bech32: {nsec}")

This final example utilizes the same seed as for the previous example, but also includes a passphrase. It illustrates the effect of inclusion of a passphrase on the key derivation.

# Advanced (with accounts) from the same wordlist with in inclusion of passphrase
words = "leader monkey parrot ring guide accident before fence cannon height naive bean"
passphrase = "RustNostr"
print("Accounts (0-5) from 12 word Seed Phrase (with passphrase):")
print(f" Seed Words (12): {words}")
print(f" Passphrase     : {passphrase}")
print(" Accounts (0-5) :")

# Use Seed Phrase and account to multiple Nostr keys
for account in range(0,6):
    nsec = Keys.from_mnemonic(words, passphrase, account).secret_key().to_bech32()
    print(f"     Account #{account} bech32: {nsec}")
JavaScript

Using the fromMnemonic() method in conjunction with the Keys class to derived a basic set of Nostr keys from a 24 word seed phrase.

Note that this example uses the generateMnemonic() method from the bip39 package, a commonly used JavaScript implementation of Bitcoin BIP39, to randomly generate example seed phrases.

// Generate random Seed Phrase (24 words e.g. 256 bits entropy)
let words256 = generateMnemonic(256);
console.log("Generated Random Seed Phrase and Derived Keys:");
console.log(`\t - Seed Words (24): ${words256}`);
let passphrase256 = "";

// Use Seed Phrase to generate basic Nostr keys
let keys256 = Keys.fromMnemonic(words256, passphrase256);

// Print Results
console.log(`\t - Private (hex)  : ${keys256.secretKey.toHex()}`);
console.log(`\t - Private (nsec) : ${keys256.secretKey.toBech32()}`);
console.log(`\t - Public (hex)   : ${keys256.publicKey.toHex()}`);
console.log(`\t - Public (npub)  : ${keys256.publicKey.toBech32()}`);

As well as deriving basic keys from a 24 word seed we can also use seed phrases of other lengths such as 18 words or, as in this example, 12 words.

// Generate random Seed Phrase (12 words e.g. 128 bits entropy)
let words128 = generateMnemonic(128);
console.log("Generated Random Seed Phrase and Derived Keys:");
console.log(`\t - Seed Words (12): ${words128}`);
let passphrase128 = "";

// Use Seed Phrase to generate basic Nostr keys
let keys128 = Keys.fromMnemonic(words128, passphrase128);

// Print Results
console.log(`\t - Private (hex)  : ${keys128.secretKey.toHex()}`);
console.log(`\t - Private (nsec) : ${keys128.secretKey.toBech32()}`);
console.log(`\t - Public (hex)   : ${keys128.publicKey.toHex()}`);
console.log(`\t - Public (npub)  : ${keys128.publicKey.toBech32()}`);

Advanced key derivation functionality (for accounts) can be accessed by the fromMnemonic() method. To do this we use the account argument which accepts an integer to specify the derivation path.

// Advanced (with accounts) from the same wordlist
let words = "leader monkey parrot ring guide accident before fence cannon height naive bean";
let passphrase  = "";
console.log("Generated Accounts:");
console.log(`\t - Seed Words (12): ${words}`);

// Use Seed Phrase and account to multiple Nostr keys
for (let account = 0; account < 6; account++) {
    let nsec = Keys.fromMnemonic(words, passphrase, account).secretKey.toBech32();
    console.log(`\t - Private (nsec) Account #${account}: ${nsec}`);
}

This final example utilizes the same seed as for the previous example, but also includes a passphrase. It illustrates the effect of inclusion of a passphrase on the key derivation.

// Advanced (with accounts) from the same wordlist with in inclusion of PassPhrase
words = "leader monkey parrot ring guide accident before fence cannon height naive bean";
passphrase = "RustNostr";
console.log("Generated Accounts:");
console.log(`\t - Seed Words (12): ${words}`);

// Use Seed Phrase, passphrase and account to multiple Nostr keys
for (let account = 0; account < 6; account++) {
    let nsec = Keys.fromMnemonic(words, passphrase, account).secretKey.toBech32();
    console.log(`\t - Private (nsec) Account #${account}: ${nsec}`);
}
Kotlin

TODO

Swift

TODO

Flutter

TODO