seedify

package module
v1.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 36 Imported by: 0

README

seedify

Go Reference Build Lint

Generate deterministic BIP-39 seed phrases from Ed25519 SSH keys, and derive wallet addresses for 20+ blockchain networks.

seedify is both a Go library for programmatic use and a CLI tool for interactive use.

Features

  • Generate BIP-39 mnemonic phrases (12, 15, 18, 21, or 24 words) from Ed25519 keys
  • Generate 16-word Polyseed phrases for Monero
  • Derive wallet addresses and keys for 20+ chains from a single mnemonic
  • Deterministic output -- same key always produces the same phrase
  • Optional seed passphrase for additional entropy
  • Brave Sync 25th-word support
Supported Chains
Chain Address Type Derivation
Bitcoin Legacy P2PKH, SegWit P2SH-P2WPKH, Native SegWit P2WPKH, Silent Payments, Multisig (1-of-1) BIP44/49/84/48/47
Nostr npub/nsec NIP-06 (m/44'/1237'/0'/0/0)
Monero Primary + subaddresses Polyseed
Ethereum EVM address BIP44 (m/44'/60'/0'/0/0)
Solana Ed25519 address BIP44 (m/44'/501'/0'/0')
Tron Base58Check address BIP44 (m/44'/195'/0'/0/0)
Litecoin Native SegWit BIP84
Dogecoin P2PKH BIP44
Zcash Transparent t-addr BIP44
Cosmos Bech32 (cosmos1...) BIP44 (m/44'/118'/0'/0/0)
Noble Bech32 (noble1...) BIP44 (m/44'/118'/0'/0/0)
Stellar StrKey (G...) BIP44 (m/44'/148'/0')
Ripple Base58 (r...) BIP44 (m/44'/144'/0'/0/0)
Sui Hex (0x...) BIP44 (m/44'/784'/0'/0'/0')
Arbitrum, Avalanche, Base, BNB Chain, Cronos, Optimism, Polygon Same as Ethereum BIP44 (m/44'/60'/0'/0/0)

Install

As a Go Library
go get github.com/complex-gh/seedify@latest
As a CLI Tool

Homebrew (macOS/Linux):

brew install complex-gh/tap/seedify

Go install:

go install github.com/complex-gh/seedify/cmd/seedify@latest

Docker:

docker run --rm -v ~/.ssh:/root/.ssh:ro ghcr.io/complex-gh/seedify /root/.ssh/id_ed25519

Binary releases: download from the Releases page.

Library Usage

Generate a Mnemonic from an Ed25519 Key
package main

import (
	"crypto/ed25519"
	"fmt"
	"log"

	"github.com/complex-gh/seedify"
)

func main() {
	// Given an Ed25519 private key (e.g. parsed from an SSH key file):
	var key ed25519.PrivateKey // = ...

	// Generate a 24-word BIP-39 mnemonic
	mnemonic, err := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(mnemonic)
}
Mnemonic Generation
// 12-word BIP-39
m12, _ := seedify.ToMnemonicWithLength(&key, 12, "", false, 0)

// 16-word Polyseed (with birthday timestamp for Monero)
m16, _ := seedify.ToMnemonicWithLength(&key, 16, "", false, seedify.PolyseedDefaultBirthday)

// 24-word BIP-39 with additional seed passphrase
m24, _ := seedify.ToMnemonicWithLength(&key, 24, "my-extra-entropy", false, 0)

// 24-word with a custom prefix (generates different words)
mPfx, _ := seedify.ToMnemonicWithPrefix(&key, 24, "", "wallet", 0)

// Brave Sync 25-word phrase (24 words + daily rotating 25th word)
brave, _ := seedify.ToMnemonicWithBraveSync(&key, "")

// Get the Brave Sync 25th word for today
word, _ := seedify.BraveSync25thWord()

Valid word counts: 12, 15, 16 (Polyseed), 18, 21, 24.

Derive Nostr Keys (NIP-06)
// From a BIP-39 mnemonic -- returns npub, nsec, hex pubkey, hex privkey
keys, err := seedify.DeriveNostrKeysWithHex(mnemonic, "")
fmt.Println(keys.Npub)       // npub1...
fmt.Println(keys.Nsec)       // nsec1...
fmt.Println(keys.PubKeyHex)  // 64-char hex
fmt.Println(keys.PrivKeyHex) // 64-char hex

// Simpler variant returning only npub/nsec strings
npub, nsec, err := seedify.DeriveNostrKeys(mnemonic, "")

// Directly from an Ed25519 key (no mnemonic needed)
npub, nsec, err := seedify.DeriveNostrKeysFromEd25519(&key)
Derive Bitcoin Addresses and Keys
// Single addresses
legacy, _  := seedify.DeriveBitcoinAddress(mnemonic, "")              // 1...  (P2PKH, BIP44)
segwit, _  := seedify.DeriveBitcoinAddressSegwit(mnemonic, "")        // 3...  (P2SH-P2WPKH, BIP49)
native, _  := seedify.DeriveBitcoinAddressNativeSegwit(mnemonic, "")  // bc1q... (P2WPKH, BIP84)
sp, _      := seedify.DeriveSilentPaymentAddress(mnemonic, "")        // sp1...

// Address + WIF private key
legacyKeys, _ := seedify.DeriveBitcoinLegacyKeys(mnemonic, "")
fmt.Println(legacyKeys.Address)    // 1...
fmt.Println(legacyKeys.PrivateWIF) // 5... or K.../L...

segwitKeys, _      := seedify.DeriveBitcoinSegwitKeys(mnemonic, "")
nativeSegwitKeys, _ := seedify.DeriveBitcoinNativeSegwitKeys(mnemonic, "")

// Extended keys (xpub/xprv, ypub/yprv, zpub/zprv)
masterExt, _ := seedify.DeriveBitcoinMasterExtendedKeys(mnemonic, "")
legacyExt, _ := seedify.DeriveBitcoinLegacyExtendedKeys(mnemonic, "")
segwitExt, _ := seedify.DeriveBitcoinSegwitExtendedKeys(mnemonic, "")
nativeExt, _ := seedify.DeriveBitcoinNativeSegwitExtendedKeys(mnemonic, "")

// Master fingerprint (4-byte hex)
fingerprint, _ := seedify.DeriveBitcoinMasterFingerprint(mnemonic, "")

// Multisig 1-of-1 keys
msLegacy, _ := seedify.DeriveBitcoinMultisigLegacyKeys(mnemonic, "")
msSegwit, _ := seedify.DeriveBitcoinMultisigSegwitKeys(mnemonic, "")
msNative, _ := seedify.DeriveBitcoinMultisigNativeSegwitKeys(mnemonic, "")

// Multisig extended keys (Ypub/Yprv, Zpub/Zprv with xpub/xprv equivalents)
msLegacyExt, _ := seedify.DeriveBitcoinMultisigLegacyExtendedKeys(mnemonic, "")
msSegwitExt, _ := seedify.DeriveBitcoinMultisigSegwitExtendedKeys(mnemonic, "")
msNativeExt, _ := seedify.DeriveBitcoinMultisigNativeSegwitExtendedKeys(mnemonic, "")

// PayNym / BIP-47 payment code
paynym, _ := seedify.DerivePayNym(mnemonic, "")
fmt.Println(paynym.PaymentCode)         // PM8T...
fmt.Println(paynym.NotificationAddress) // 1...
Derive Other Chain Addresses
eth, _     := seedify.DeriveEthereumAddress(mnemonic, "")  // 0x...
sol, _     := seedify.DeriveSolanaAddress(mnemonic, "")     // Base58
tron, _    := seedify.DeriveTronAddress(mnemonic, "")       // T...
ltc, _     := seedify.DeriveLitecoinAddress(mnemonic, "")   // ltc1...
doge, _    := seedify.DeriveDogecoinAddress(mnemonic, "")   // D...
zec, _     := seedify.DeriveZcashAddress(mnemonic, "")      // t1...
xrp, _     := seedify.DeriveRippleAddress(mnemonic, "")     // r...
cosmos, _  := seedify.DeriveCosmosAddress(mnemonic, "")     // cosmos1...
noble, _   := seedify.DeriveNobleAddress(mnemonic, "")      // noble1...
xlm, _     := seedify.DeriveStellarAddress(mnemonic, "")    // G...
sui, _     := seedify.DeriveSuiAddress(mnemonic, "")        // 0x...

EVM-compatible chains (Arbitrum, Avalanche, Base, BNB Chain, Cronos, Optimism, Polygon) share the same address as Ethereum -- call DeriveEthereumAddress.

Derive Monero Addresses (from Polyseed)
// Generate a 16-word Polyseed mnemonic first
polyseed, _ := seedify.ToMnemonicWithLength(&key, 16, "", false, seedify.PolyseedDefaultBirthday)

// Primary address
addr, _ := seedify.DeriveMoneroAddress(polyseed) // 4...

// Subaddress at a specific index
sub, _ := seedify.DeriveMoneroSubaddressAtIndex(polyseed, 1) // 8...

// Primary + multiple subaddresses in one call
keys, _ := seedify.DeriveMoneroKeys(polyseed, 5)
fmt.Println(keys.PrimaryAddress) // 4...
fmt.Println(keys.Subaddresses)   // [8..., 8..., 8..., 8..., 8...]

API Reference

The full API documentation is available on pkg.go.dev.

Constants
Constant Description
PolyseedDefaultBirthday Default Polyseed birthday (1 Jan 2026 00:00 UTC). Use for deterministic 16-word output. Pass 0 for current time.
Types
Type Fields Description
NostrKeys Npub, Nsec, PubKeyHex, PrivKeyHex Nostr key pair in bech32 and hex formats
BitcoinKeys Address, PrivateWIF Bitcoin address with its WIF-encoded private key
BitcoinExtendedKeys ExtendedPublicKey, ExtendedPrivateKey Account-level extended keys (xpub/xprv, ypub/yprv, zpub/zprv)
BitcoinMultisigExtendedKeys ExtendedPublicKey, ExtendedPrivateKey, StandardPublicKey, StandardPrivateKey Multisig extended keys in both specific (Ypub/Zpub) and standard (xpub) formats
PayNymKeys PaymentCode, NotificationAddress BIP-47 payment code and notification address
MoneroKeys PrimaryAddress, Subaddresses Monero primary address and subaddresses
Functions
Mnemonic Generation
Function Description
ToMnemonicWithLength(key, wordCount, seedPassphrase, brave, birthday) Generate a mnemonic of the given word count (12/15/16/18/21/24)
ToMnemonicWithPrefix(key, wordCount, seedPassphrase, prefix, birthday) Generate a mnemonic with a custom prefix for domain separation
ToMnemonicWithBraveSync(key, seedPassphrase) Generate a 25-word Brave Sync phrase
BraveSync25thWord() Get today's Brave Sync 25th word
BraveSync25thWordForDate(date) Get the Brave Sync 25th word for a specific date
Nostr (NIP-06)
Function Description
DeriveNostrKeysWithHex(mnemonic, bip39Passphrase) Derive full Nostr key set (npub, nsec, hex) from mnemonic
DeriveNostrKeys(mnemonic, bip39Passphrase) Derive npub/nsec strings from mnemonic
DeriveNostrKeysFromEd25519(key) Derive npub/nsec directly from an Ed25519 key
Bitcoin
Function Description
DeriveBitcoinAddress(mnemonic, passphrase) Legacy P2PKH address (BIP44)
DeriveBitcoinAddressSegwit(mnemonic, passphrase) SegWit P2SH-P2WPKH address (BIP49)
DeriveBitcoinAddressNativeSegwit(mnemonic, passphrase) Native SegWit P2WPKH address (BIP84)
DeriveBitcoinAddressNativeSegwitAtIndex(mnemonic, passphrase, index) Native SegWit address at a specific index
DeriveSilentPaymentAddress(mnemonic, passphrase) BIP-352 Silent Payment address
DeriveBitcoinLegacyKeys(mnemonic, passphrase) Legacy address + WIF key
DeriveBitcoinSegwitKeys(mnemonic, passphrase) SegWit address + WIF key
DeriveBitcoinNativeSegwitKeys(mnemonic, passphrase) Native SegWit address + WIF key
DeriveBitcoinMasterFingerprint(mnemonic, passphrase) 4-byte master fingerprint (hex)
DeriveBitcoinMasterExtendedKeys(mnemonic, passphrase) Master xpub/xprv at path m
DeriveBitcoinLegacyExtendedKeys(mnemonic, passphrase) Account xpub/xprv (BIP44)
DeriveBitcoinSegwitExtendedKeys(mnemonic, passphrase) Account ypub/yprv (BIP49)
DeriveBitcoinNativeSegwitExtendedKeys(mnemonic, passphrase) Account zpub/zprv (BIP84)
DeriveBitcoinMultisigLegacyKeys(mnemonic, passphrase) Multisig legacy address + WIF (BIP48)
DeriveBitcoinMultisigSegwitKeys(mnemonic, passphrase) Multisig SegWit address + WIF (BIP48)
DeriveBitcoinMultisigNativeSegwitKeys(mnemonic, passphrase) Multisig native SegWit address + WIF (BIP48)
DeriveBitcoinMultisigLegacyExtendedKeys(mnemonic, passphrase) Multisig legacy xpub/xprv (BIP48)
DeriveBitcoinMultisigSegwitExtendedKeys(mnemonic, passphrase) Multisig SegWit Ypub/Yprv + xpub/xprv (BIP48)
DeriveBitcoinMultisigNativeSegwitExtendedKeys(mnemonic, passphrase) Multisig native SegWit Zpub/Zprv + xpub/xprv (BIP48)
DerivePayNym(mnemonic, passphrase) BIP-47 PayNym payment code + notification address
Monero
Function Description
DeriveMoneroAddress(mnemonic) Primary Monero address from a 16-word Polyseed
DeriveMoneroSubaddressAtIndex(mnemonic, index) Monero subaddress at a given index
DeriveMoneroKeys(mnemonic, numSubaddresses) Primary address + N subaddresses
Other Chains
Function Description
DeriveEthereumAddress(mnemonic, passphrase) Ethereum / EVM address
DeriveSolanaAddress(mnemonic, passphrase) Solana address
DeriveTronAddress(mnemonic, passphrase) Tron address
DeriveLitecoinAddress(mnemonic, passphrase) Litecoin native SegWit address
DeriveDogecoinAddress(mnemonic, passphrase) Dogecoin address
DeriveZcashAddress(mnemonic, passphrase) Zcash transparent address
DeriveRippleAddress(mnemonic, passphrase) Ripple (XRP) address
DeriveCosmosAddress(mnemonic, passphrase) Cosmos address
DeriveNobleAddress(mnemonic, passphrase) Noble address
DeriveStellarAddress(mnemonic, passphrase) Stellar address
DeriveSuiAddress(mnemonic, passphrase) Sui address

CLI Usage

seedify <key-path> [flags]
seedify ~/.ssh/id_ed25519
seedify ~/.ssh/id_ed25519 --words 12
seedify ~/.ssh/id_ed25519 --words 12,24
seedify ~/.ssh/id_ed25519 --nostr
seedify ~/.ssh/id_ed25519 --btc --eth --sol
seedify ~/.ssh/id_ed25519 --full
seedify ~/.ssh/id_ed25519 --brave
seedify ~/.ssh/id_ed25519 --xmr --polyseed-year 2025
cat ~/.ssh/id_ed25519 | seedify --words 18
Flags
Flag Description
-w, --words Word counts to generate, comma-separated (12,15,16,18,21,24)
--seed-passphrase Combine with SSH key seed for additional entropy
--brave Generate 25-word Brave Sync phrase
--full Print all word counts and all chain derivations
--nostr Derive Nostr keys (npub/nsec)
--btc Derive Bitcoin addresses
--eth Derive Ethereum address
--zec Derive Zcash address
--sol Derive Solana address
--tron Derive Tron address
--xmr Derive Monero address from Polyseed
--zenprofile Output public keys and addresses as DNS JSON
--publish Publish NIP-78 event to relays (with --zenprofile)
--polyseed-year Override Polyseed birthday year (default: current year)
-l, --language Mnemonic language (default: en)
Security Tip

Add a leading space before the command to prevent it from being saved in your shell history:

 seedify ~/.ssh/id_ed25519

Most shells (bash, zsh) ignore commands that start with a space when HISTCONTROL=ignorespace or HIST_IGNORE_SPACE is set.

Security Considerations

  • Password-protected keys only: The CLI requires SSH keys to be password-protected. Unprotected keys are rejected.
  • One-way derivation: Seed phrases cannot be used to recover the original SSH key. The derivation is intentionally irreversible.
  • Deterministic output: The same key + passphrase always produces the same mnemonic. This means the mnemonic is only as secure as the SSH key and passphrase.
  • Seed passphrase: Use --seed-passphrase (CLI) or the seedPassphrase parameter (library) to add entropy beyond the SSH key alone. Different passphrases produce completely different mnemonics.

License

MIT -- Copyright (c) 2025-2026 complex (complex@ft.hn)

Documentation

Overview

Package seedify provides functions to create seed phrases deterministically from an SSH key. This package does not provide functionality to recover the original SSH key from the seed phrase.

The purpose of seedify is to generate seed phrases of various lengths (12, 15, 16, 18, 21, or 24 words) from an ed25519 private key. These phrases can be used for various purposes.

Index

Examples

Constants

View Source
const (

	// PolyseedDefaultBirthday is the default polyseed birthday (1 Jan 2026 00:00 UTC).
	// Using a fixed timestamp ensures deterministic mnemonic output.
	// Pass 0 to use the current time (non-deterministic).
	PolyseedDefaultBirthday = uint64(1767225600)
)

Constants for mnemonic generation.

Variables

This section is empty.

Functions

func BraveSync25thWord

func BraveSync25thWord() (string, error)

BraveSync25thWord returns the 25th word for Brave Sync based on the current date. The 25th word changes daily and is calculated from the epoch date "Tue, 10 May 2022 00:00:00 GMT". The number of days since the epoch is used as an index into the BIP39 English word list.

This function replicates the logic from the JavaScript implementation at https://alexeybarabash.github.io/25th-brave-sync-word/

Returns an error if the current date is before the epoch date or if the calculated index is out of bounds for the BIP39 word list.

func BraveSync25thWordForDate

func BraveSync25thWordForDate(date time.Time) (string, error)

BraveSync25thWordForDate returns the 25th word for Brave Sync for a specific date. This allows you to get the 25th word for any date, not just today.

The date parameter should be in UTC. The number of days since the epoch "Tue, 10 May 2022 00:00:00 GMT" is used as an index into the BIP39 English word list.

Returns an error if the provided date is before the epoch date or if the calculated index is out of bounds for the BIP39 word list.

func DeriveBitcoinAddress

func DeriveBitcoinAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveBitcoinAddress derives a Bitcoin address from a BIP39 mnemonic phrase. The function follows BIP44 standard with derivation path m/44'/0'/0'/0/0. It returns a P2PKH address (starts with "1") for Bitcoin mainnet.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Bitcoin P2PKH address
  • error: Any error that occurred during derivation

func DeriveBitcoinAddressNativeSegwit

func DeriveBitcoinAddressNativeSegwit(mnemonic string, bip39Passphrase string) (string, error)

DeriveBitcoinAddressNativeSegwit derives a P2WPKH (Native SegWit) Bitcoin address. The function follows BIP84 standard with derivation path m/84'/0'/0'/0/0. It returns a Bech32 address (starts with "bc1q") for Bitcoin mainnet.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Bitcoin P2WPKH address (starts with "bc1q")
  • error: Any error that occurred during derivation
Example
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, _ := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)

	addr, err := seedify.DeriveBitcoinAddressNativeSegwit(mnemonic, "")
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("starts with bc1q:", addr[:4] == "bc1q")
}

func DeriveBitcoinAddressNativeSegwitAtIndex

func DeriveBitcoinAddressNativeSegwitAtIndex(mnemonic string, bip39Passphrase string, addressIndex uint32) (string, error)

DeriveBitcoinAddressNativeSegwitAtIndex derives a P2WPKH address at the given address index. Path: m/84'/0'/0'/0/{addressIndex}. Index 1-19 is typically used for DNS output.

func DeriveBitcoinAddressSegwit

func DeriveBitcoinAddressSegwit(mnemonic string, bip39Passphrase string) (string, error)

DeriveBitcoinAddressSegwit derives a P2SH-P2WPKH (Nested SegWit) Bitcoin address. The function follows BIP49 standard with derivation path m/49'/0'/0'/0/0. It returns a P2SH-wrapped SegWit address (starts with "3") for Bitcoin mainnet.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Bitcoin P2SH-P2WPKH address (starts with "3")
  • error: Any error that occurred during derivation

func DeriveBitcoinMasterFingerprint

func DeriveBitcoinMasterFingerprint(mnemonic string, bip39Passphrase string) (string, error)

DeriveBitcoinMasterFingerprint derives the master key fingerprint from a BIP39 mnemonic. The fingerprint is the first 4 bytes of HASH160(compressed_master_public_key), encoded as a lowercase hex string (8 characters). This is commonly used in wallet descriptors and PSBTs (e.g., [d219d86d/48'/0'/0'/2']xpub...).

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • fingerprint: The 4-byte master fingerprint as a lowercase hex string
  • error: Any error that occurred during derivation

func DeriveCosmosAddress

func DeriveCosmosAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveCosmosAddress derives a Cosmos (ATOM) address from a BIP39 mnemonic. The function follows BIP44 standard with derivation path m/44'/118'/0'/0/0. It returns a Bech32 address with the "cosmos" prefix (starts with "cosmos1").

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Cosmos address (starts with "cosmos1")
  • error: Any error that occurred during derivation

func DeriveDogecoinAddress

func DeriveDogecoinAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveDogecoinAddress derives a Dogecoin P2PKH address from a BIP39 mnemonic. The function follows BIP44 standard with derivation path m/44'/3'/0'/0/0. It returns a Base58Check address (starts with "D") for Dogecoin mainnet.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Dogecoin P2PKH address (starts with "D")
  • error: Any error that occurred during derivation

func DeriveEd25519KeyFromRSA added in v1.19.0

func DeriveEd25519KeyFromRSA(key *rsa.PrivateKey) (ed25519.PrivateKey, error)

DeriveEd25519KeyFromRSA deterministically derives an Ed25519 private key from an RSA private key. The derivation uses RSASeedBytes (SHA256 of the prime factors P and Q) as the Ed25519 seed, making the output stable for any given RSA key.

Security note: if the RSA key is compromised, the derived Ed25519 key is also compromised. This is a one-way derivation; the original RSA key cannot be recovered from the output.

func DeriveEthereumAddress

func DeriveEthereumAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveEthereumAddress derives an Ethereum address from a BIP39 mnemonic phrase. The function follows BIP44 standard with derivation path m/44'/60'/0'/0/0. It returns a checksummed Ethereum address (starts with "0x").

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Ethereum address with 0x prefix
  • error: Any error that occurred during derivation
Example
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, _ := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)

	addr, err := seedify.DeriveEthereumAddress(mnemonic, "")
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("starts with 0x:", addr[:2] == "0x")
	fmt.Println("length:", len(addr))
}

func DeriveLitecoinAddress

func DeriveLitecoinAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveLitecoinAddress derives a Litecoin native SegWit (P2WPKH) address from a BIP39 mnemonic. The function follows BIP84 standard with derivation path m/84'/2'/0'/0/0. It returns a Bech32 address (starts with "ltc1") for Litecoin mainnet.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Litecoin P2WPKH address (starts with "ltc1")
  • error: Any error that occurred during derivation

func DeriveMoneroAddress

func DeriveMoneroAddress(mnemonic string) (string, error)

DeriveMoneroAddress derives a Monero address from a polyseed mnemonic phrase. The function decodes the polyseed to extract the seed bytes, then derives the Monero spend and view keys from it.

Parameters:

  • mnemonic: A valid 16-word polyseed mnemonic phrase

Returns:

  • address: The Monero primary address (starts with "4")
  • error: Any error that occurred during derivation

func DeriveMoneroSubaddressAtIndex

func DeriveMoneroSubaddressAtIndex(mnemonic string, index uint32) (string, error)

DeriveMoneroSubaddressAtIndex derives a Monero receiving subaddress at the given index. Index 0 maps to subaddress (0,1), index 1 to (0,2), etc. Valid range: 0-19 for DNS output.

func DeriveNobleAddress

func DeriveNobleAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveNobleAddress derives a Noble address from a BIP39 mnemonic. Noble uses the same key derivation as Cosmos (coin type 118) but with "noble" bech32 prefix.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Noble address (starts with "noble1")
  • error: Any error that occurred during derivation

func DeriveNostrKeys

func DeriveNostrKeys(mnemonic string, bip39Passphrase string) (npub string, nsec string, err error)

DeriveNostrKeys derives Nostr keys (npub/nsec) from a BIP39 mnemonic phrase. The function follows NIP-06 standard: it converts the mnemonic to a BIP39 seed, then uses BIP32 hierarchical derivation with path m/44'/1237'/0'/0/0 to derive the Nostr private key. The keys are encoded to npub/nsec format using bech32.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • npub: The Nostr public key in bech32 format (starts with "npub1")
  • nsec: The Nostr private key in bech32 format (starts with "nsec1")
  • error: Any error that occurred during derivation

func DeriveNostrKeysFromEd25519

func DeriveNostrKeysFromEd25519(key *ed25519.PrivateKey) (npub string, nsec string, err error)

DeriveNostrKeysFromEd25519 derives Nostr keys (npub/nsec) directly from an Ed25519 private key. This function is used to derive Nostr keys from SSH keys without going through seed phrases.

Parameters:

  • key: An Ed25519 private key (e.g., from an SSH key)

Returns:

  • npub: The Nostr public key in bech32 format (starts with "npub1")
  • nsec: The Nostr private key in bech32 format (starts with "nsec1")
  • error: Any error that occurred during derivation

func DeriveNostrKeysFromRSA added in v1.19.0

func DeriveNostrKeysFromRSA(key *rsa.PrivateKey) (npub string, nsec string, err error)

DeriveNostrKeysFromRSA derives Nostr keys (npub/nsec) directly from an RSA private key. A 32-byte seed is extracted via RSASeedBytes (SHA256 of the two prime factors P and Q), then used as the secp256k1 private scalar to derive a valid Nostr key pair.

Parameters:

  • key: An RSA private key (e.g., from an SSH key)

Returns:

  • npub: The Nostr public key in bech32 format (starts with "npub1")
  • nsec: The Nostr private key in bech32 format (starts with "nsec1")
  • error: Any error that occurred during derivation

func DeriveRSAKeyFromEd25519 added in v1.19.0

func DeriveRSAKeyFromEd25519(key *ed25519.PrivateKey, bits int) (*rsa.PrivateKey, error)

DeriveRSAKeyFromEd25519 deterministically derives an RSA private key from an Ed25519 private key. The derivation domain-separates the Ed25519 seed with the label "seedify:rsa-from-ed25519:", hashes it with SHA-256 to produce a 32-byte AES-256 key, and feeds an AES-256-CTR stream as the source of randomness for prime generation. This ensures the same Ed25519 key and bit size always produce the same RSA key.

bits must be 2048, 3072, or 4096. 4096 is strongly recommended. This function is computationally expensive because it involves prime search.

Security note: if the Ed25519 key is compromised, the derived RSA key is also compromised. This is a one-way derivation; the original Ed25519 key cannot be recovered from the output.

func DeriveRippleAddress

func DeriveRippleAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveRippleAddress derives an XRP Ledger address from a BIP39 mnemonic. The function follows BIP44 standard with derivation path m/44'/144'/0'/0/0. It returns a Ripple Base58Check address (starts with "r").

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The XRP address (starts with "r")
  • error: Any error that occurred during derivation

func DeriveSilentPaymentAddress

func DeriveSilentPaymentAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveSilentPaymentAddress derives a BIP 352 Silent Payment (sp1) address from a BIP39 mnemonic. The function follows BIP 352 derivation paths:

  • scan key: m/352'/0'/0'/1'/0
  • spend key: m/352'/0'/0'/0'/0

It returns a bech32m-encoded address (starts with "sp1") for Bitcoin mainnet. Silent Payments are privacy-preserving static addresses: each payment appears on-chain as a unique Taproot address, making it impossible for observers to link payments.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Bitcoin Silent Payment address (starts with "sp1")
  • error: Any error that occurred during derivation

func DeriveSolanaAddress

func DeriveSolanaAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveSolanaAddress derives a Solana address from a BIP39 mnemonic phrase. The function follows SLIP-0010/BIP44 standard with derivation path m/44'/501'/0'/0'. Solana uses Ed25519 keys, so all path components are hardened. It returns a Base58-encoded public key as the Solana address.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Solana address (Base58-encoded public key)
  • error: Any error that occurred during derivation

func DeriveStellarAddress

func DeriveStellarAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveStellarAddress derives a Stellar (XLM) address from a BIP39 mnemonic. The function follows SEP-0005 standard with derivation path m/44'/148'/0' using SLIP-0010 Ed25519 derivation. It returns a StrKey-encoded public key (starts with "G").

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Stellar address (starts with "G")
  • error: Any error that occurred during derivation

func DeriveSuiAddress

func DeriveSuiAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveSuiAddress derives a Sui address from a BIP39 mnemonic. The function follows SLIP-0010 Ed25519 derivation with path m/44'/784'/0'/0'/0'. It returns an address formatted as "0x" + hex(Blake2b-256(0x00 || pubkey)).

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Sui address (starts with "0x")
  • error: Any error that occurred during derivation

func DeriveTronAddress

func DeriveTronAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveTronAddress derives a Tron address from a BIP39 mnemonic phrase. The function follows BIP44 standard with derivation path m/44'/195'/0'/0/0. Tron uses the same secp256k1 key derivation and Keccak256 address computation as Ethereum, but encodes the address using Base58Check with a 0x41 prefix instead of hex with a 0x prefix. The resulting address starts with "T".

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Tron address (Base58Check-encoded, starts with "T")
  • error: Any error that occurred during derivation

func DeriveZcashAddress

func DeriveZcashAddress(mnemonic string, bip39Passphrase string) (string, error)

DeriveZcashAddress derives a Zcash transparent P2PKH (t1) address from a BIP39 mnemonic. The function follows BIP44 standard with derivation path m/44'/133'/0'/0/0 (coin type 133 = Zcash per SLIP-0044). It returns a Base58Check address (starts with "t1") for Zcash mainnet.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • address: The Zcash transparent P2PKH address (starts with "t1")
  • error: Any error that occurred during derivation

func RSASeedBytes added in v1.19.0

func RSASeedBytes(key *rsa.PrivateKey) ([]byte, error)

RSASeedBytes derives a deterministic 32-byte seed from an RSA private key by hashing the two secret prime factors with SHA-256: SHA256(P || Q). P and Q are the root secrets of an RSA key pair — all other components (N, D, Dp, Dq, Qinv) are derived from them.

Returns an error if the key does not have at least two prime factors.

func ToMnemonicWithBraveSync

func ToMnemonicWithBraveSync(key *ed25519.PrivateKey, seedPassphrase string) (string, error)

ToMnemonicWithBraveSync generates a 24-word mnemonic with the "brave" prefix and appends the 25th word from Brave Sync. This creates a 25-word phrase suitable for use with Brave Sync.

The function generates 24 words using the same logic as ToMnemonicWithLength with the brave flag set, then appends the current day's 25th word from Brave Sync.

func ToMnemonicWithBraveSyncFromRSA added in v1.19.0

func ToMnemonicWithBraveSyncFromRSA(key *rsa.PrivateKey, seedPassphrase string) (string, error)

ToMnemonicWithBraveSyncFromRSA is the RSA analogue of ToMnemonicWithBraveSync. It generates a 24-word mnemonic with the "brave" prefix from an RSA key and appends the current day's 25th Brave Sync word.

func ToMnemonicWithLength

func ToMnemonicWithLength(key *ed25519.PrivateKey, wordCount int, seedPassphrase string, brave bool, birthday uint64) (string, error)

ToMnemonicWithLength takes an ed25519 private key and returns a mnemonic phrase of the specified word count. This is an auxiliary utility function. The generated phrases cannot be used with FromMnemonic to recover the original key if the word count is less than 24.

If seedPassphrase is provided (non-empty), it will be combined with the SSH key seed to add additional entropy: ENTROPY(seed-passphrase) + ENTROPY(ssh-key).

The word count is prepended to the entropy to ensure different word counts generate completely different words, not just truncated versions of the same phrase. Exception: For 24 words (when brave is false), the raw seed is used directly without prepending word count or hashing.

If brave is true, the hash of "brave" is prepended to the entropy (similar to word count) to generate a different set of words.

birthday is a Unix timestamp used as the polyseed creation date for 16-word mnemonics. Use PolyseedEpoch for deterministic output, or 0 for the current time. This parameter is ignored for non-polyseed word counts.

Valid word counts are: 12, 15, 16, 18, 21, or 24. The entropy size is determined by the word count:

  • 12 words = 128 bits (16 bytes) - BIP39
  • 15 words = 160 bits (20 bytes) - BIP39
  • 16 words = 150 bits (19 bytes) - Polyseed format
  • 18 words = 192 bits (24 bytes) - BIP39
  • 21 words = 224 bits (28 bytes) - BIP39
  • 24 words = 256 bits (32 bytes) - BIP39
Example
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, err := seedify.ToMnemonicWithLength(&key, 12, "", false, 0)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("word count: 12")
	fmt.Println("mnemonic:", mnemonic)
	// Output is deterministic but depends on the key bytes,
	// so we just verify it ran without error.
}
Example (Polyseed)
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, err := seedify.ToMnemonicWithLength(&key, 16, "", false, seedify.PolyseedDefaultBirthday)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("word count: 16")
	fmt.Println("mnemonic:", mnemonic)
}
Example (TwentyFourWords)
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, err := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("word count: 24")
	fmt.Println("mnemonic:", mnemonic)
}
Example (WithSeedPassphrase)
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	m1, _ := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)
	m2, _ := seedify.ToMnemonicWithLength(&key, 24, "my-secret", false, 0)

	// Different passphrases produce different mnemonics from the same key.
	fmt.Println("same mnemonic:", m1 == m2)
}
Output:
same mnemonic: false

func ToMnemonicWithLengthFromRSA added in v1.19.0

func ToMnemonicWithLengthFromRSA(key *rsa.PrivateKey, wordCount int, seedPassphrase string, brave bool, birthday uint64) (string, error)

ToMnemonicWithLengthFromRSA is the RSA analogue of ToMnemonicWithLength. It extracts a 32-byte seed from the RSA private key via RSASeedBytes and delegates to the same internal mnemonic pipeline.

See ToMnemonicWithLength for parameter and word-count documentation.

func ToMnemonicWithPrefix

func ToMnemonicWithPrefix(key *ed25519.PrivateKey, wordCount int, seedPassphrase string, prefix string, birthday uint64) (string, error)

ToMnemonicWithPrefix takes an ed25519 private key and returns a mnemonic phrase of the specified word count. It is a generalization of ToMnemonicWithLength that accepts an arbitrary prefix string instead of a boolean brave flag.

If prefix is non-empty, the hash of the prefix string is prepended to the entropy (similar to how the word count is prepended) to generate a completely different set of words. This allows generating distinct seed phrases for different applications (e.g., "brave" for Brave Sync, "wallet" for Brave Wallet).

If seedPassphrase is provided (non-empty), it will be combined with the SSH key seed to add additional entropy: ENTROPY(seed-passphrase) + ENTROPY(ssh-key).

The word count is prepended to the entropy to ensure different word counts generate completely different words, not just truncated versions of the same phrase. Exception: For 24 words (when prefix is empty), the raw seed is used directly without prepending word count or hashing.

birthday is a Unix timestamp used as the polyseed creation date for 16-word mnemonics. Use PolyseedEpoch for deterministic output, or 0 for the current time. This parameter is ignored for non-polyseed word counts.

Valid word counts are: 12, 15, 16, 18, 21, or 24. The entropy size is determined by the word count:

  • 12 words = 128 bits (16 bytes) - BIP39
  • 15 words = 160 bits (20 bytes) - BIP39
  • 16 words = 150 bits (19 bytes) - Polyseed format
  • 18 words = 192 bits (24 bytes) - BIP39
  • 21 words = 224 bits (28 bytes) - BIP39
  • 24 words = 256 bits (32 bytes) - BIP39

func ToMnemonicWithPrefixFromRSA added in v1.19.0

func ToMnemonicWithPrefixFromRSA(key *rsa.PrivateKey, wordCount int, seedPassphrase string, prefix string, birthday uint64) (string, error)

ToMnemonicWithPrefixFromRSA is the RSA analogue of ToMnemonicWithPrefix. It extracts a 32-byte seed from the RSA private key via RSASeedBytes and delegates to the same internal mnemonic pipeline.

See ToMnemonicWithPrefix for parameter and word-count documentation.

Types

type BitcoinExtendedKeys

type BitcoinExtendedKeys struct {
	ExtendedPublicKey  string
	ExtendedPrivateKey string
}

BitcoinExtendedKeys contains the extended public and private keys at the account level.

func DeriveBitcoinLegacyExtendedKeys

func DeriveBitcoinLegacyExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)

DeriveBitcoinLegacyExtendedKeys derives the extended public and private keys for BIP44 Legacy. Returns xpub and xprv at the account level (m/44'/0'/0').

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinExtendedKeys: The xpub and xprv at account level
  • error: Any error that occurred during derivation

func DeriveBitcoinMasterExtendedKeys

func DeriveBitcoinMasterExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)

DeriveBitcoinMasterExtendedKeys derives the master extended public and private keys. Returns xpub and xprv at the master level (m). This is the root of the HD wallet tree, before any BIP44/49/84 derivation.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinExtendedKeys: The xpub and xprv at master level
  • error: Any error that occurred during derivation

func DeriveBitcoinMultisigLegacyExtendedKeys

func DeriveBitcoinMultisigLegacyExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)

DeriveBitcoinMultisigLegacyExtendedKeys derives extended keys for BIP48 Legacy multisig. Returns xpub and xprv at the account/script level (m/48'/0'/0'/0').

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinExtendedKeys: The xpub and xprv at account level
  • error: Any error that occurred during derivation

func DeriveBitcoinNativeSegwitExtendedKeys

func DeriveBitcoinNativeSegwitExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)

DeriveBitcoinNativeSegwitExtendedKeys derives the extended public and private keys for BIP84 Native SegWit. Returns zpub and zprv at the account level (m/84'/0'/0').

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinExtendedKeys: The zpub and zprv at account level
  • error: Any error that occurred during derivation

func DeriveBitcoinSegwitExtendedKeys

func DeriveBitcoinSegwitExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)

DeriveBitcoinSegwitExtendedKeys derives the extended public and private keys for BIP49 SegWit. Returns ypub and yprv at the account level (m/49'/0'/0').

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinExtendedKeys: The ypub and yprv at account level
  • error: Any error that occurred during derivation

type BitcoinKeys

type BitcoinKeys struct {
	Address    string
	PrivateWIF string
}

BitcoinKeys contains the address and private key (WIF) for a Bitcoin derivation.

func DeriveBitcoinLegacyKeys

func DeriveBitcoinLegacyKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)

DeriveBitcoinLegacyKeys derives a Bitcoin Legacy P2PKH address and its WIF private key. The function follows BIP44 standard with derivation path m/44'/0'/0'/0/0.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinKeys: The address and WIF-encoded private key
  • error: Any error that occurred during derivation

func DeriveBitcoinMultisigLegacyKeys

func DeriveBitcoinMultisigLegacyKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)

DeriveBitcoinMultisigLegacyKeys derives a 1-of-1 multisig P2SH address and its WIF private key. The function follows BIP48 standard with derivation path m/48'/0'/0'/0'/0/0. Script type 0' indicates P2SH (legacy multisig).

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinKeys: The P2SH multisig address and WIF-encoded private key
  • error: Any error that occurred during derivation

func DeriveBitcoinMultisigNativeSegwitKeys

func DeriveBitcoinMultisigNativeSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)

DeriveBitcoinMultisigNativeSegwitKeys derives a 1-of-1 multisig P2WSH address and its WIF private key. The function follows BIP48 standard with derivation path m/48'/0'/0'/2'/0/0. Script type 2' indicates P2WSH (native SegWit multisig).

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinKeys: The P2WSH multisig address and WIF-encoded private key
  • error: Any error that occurred during derivation

func DeriveBitcoinMultisigSegwitKeys

func DeriveBitcoinMultisigSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)

DeriveBitcoinMultisigSegwitKeys derives a 1-of-1 multisig P2SH-P2WSH address and its WIF private key. The function follows BIP48 standard with derivation path m/48'/0'/0'/1'/0/0. Script type 1' indicates P2SH-P2WSH (nested SegWit multisig).

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinKeys: The P2SH-P2WSH multisig address and WIF-encoded private key
  • error: Any error that occurred during derivation

func DeriveBitcoinNativeSegwitKeys

func DeriveBitcoinNativeSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)

DeriveBitcoinNativeSegwitKeys derives a Bitcoin Native SegWit P2WPKH address and its WIF private key. The function follows BIP84 standard with derivation path m/84'/0'/0'/0/0.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinKeys: The address and WIF-encoded private key
  • error: Any error that occurred during derivation

func DeriveBitcoinSegwitKeys

func DeriveBitcoinSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)

DeriveBitcoinSegwitKeys derives a Bitcoin SegWit P2SH-P2WPKH address and its WIF private key. The function follows BIP49 standard with derivation path m/49'/0'/0'/0/0.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinKeys: The address and WIF-encoded private key
  • error: Any error that occurred during derivation

type BitcoinMultisigExtendedKeys

type BitcoinMultisigExtendedKeys struct {
	// ExtendedPublicKey is the specific format (e.g., Ypub or Zpub)
	ExtendedPublicKey string
	// ExtendedPrivateKey is the specific format (e.g., Yprv or Zprv)
	ExtendedPrivateKey string
	// StandardPublicKey is the standard xpub format
	StandardPublicKey string
	// StandardPrivateKey is the standard xprv format
	StandardPrivateKey string
}

BitcoinMultisigExtendedKeys contains both the specific format (Ypub/Yprv or Zpub/Zprv) and the standard format (xpub/xprv) for multisig extended keys. The standard keys are nested conceptually below the specific keys.

func DeriveBitcoinMultisigNativeSegwitExtendedKeys

func DeriveBitcoinMultisigNativeSegwitExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinMultisigExtendedKeys, error)

DeriveBitcoinMultisigNativeSegwitExtendedKeys derives extended keys for BIP48 Native SegWit multisig. Returns Zpub/Zprv (SLIP-132 format) and xpub/xprv (standard format) at the account/script level (m/48'/0'/0'/2'). Uppercase Z indicates multisig P2WSH.

The standard xpub/xprv keys are provided as nested alternatives to the specific Zpub/Zprv format:

Zprv ...
|_ xprv ...

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinMultisigExtendedKeys: The Zpub/Zprv and xpub/xprv at account level
  • error: Any error that occurred during derivation

func DeriveBitcoinMultisigSegwitExtendedKeys

func DeriveBitcoinMultisigSegwitExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinMultisigExtendedKeys, error)

DeriveBitcoinMultisigSegwitExtendedKeys derives extended keys for BIP48 SegWit multisig. Returns Ypub/Yprv (SLIP-132 format) and xpub/xprv (standard format) at the account/script level (m/48'/0'/0'/1'). Uppercase Y indicates multisig P2SH-P2WSH.

The standard xpub/xprv keys are provided as nested alternatives to the specific Ypub/Yprv format:

Yprv ...
|_ xprv ...

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • BitcoinMultisigExtendedKeys: The Ypub/Yprv and xpub/xprv at account level
  • error: Any error that occurred during derivation

type DKIMKeypair added in v1.19.0

type DKIMKeypair struct {
	// PrivateKeyPEM is the RSA private key encoded as a PKCS#8 PEM block
	// ("-----BEGIN PRIVATE KEY-----"). This is the format expected by OpenDKIM,
	// rspamd, Postfix, and Exim. DKIM private keys are stored without passphrase
	// protection — secure the file with filesystem permissions (0600).
	PrivateKeyPEM []byte

	// DNSTXTRecord is the complete value for the DKIM selector DNS TXT record,
	// ready to publish under <selector>._domainkey.<domain> in TXT format.
	// Example: v=DKIM1; k=rsa; p=<base64-encoded-public-key>
	DNSTXTRecord string

	// PublicKeyBase64 is the base64-encoded DER-encoded SubjectPublicKeyInfo
	// public key, without the surrounding v=DKIM1 wrapper. This is the raw
	// value that goes in the p= field of the DNS TXT record.
	PublicKeyBase64 string
}

DKIMKeypair holds the formatted DKIM key material ready for use with a mail server.

func DeriveDKIMKeypair added in v1.19.0

func DeriveDKIMKeypair(key *ed25519.PrivateKey, selector string, bits int) (*DKIMKeypair, error)

DeriveDKIMKeypair deterministically derives an RSA keypair from an Ed25519 private key and formats the output for immediate use with a DKIM-signing mail server (OpenDKIM, rspamd, Postfix milter, Exim).

The selector is mixed into the domain-separation label as "seedify:dkim:<selector>:", so different selectors produce completely different RSA keys from the same source Ed25519 key. This makes selector-based key rotation possible without needing a new Ed25519 source key.

The private key is marshalled as a PKCS#8 PEM block ("BEGIN PRIVATE KEY"), which is the format most modern MTAs and DKIM libraries expect. No passphrase is applied because DKIM private keys are conventionally stored unencrypted and protected only by filesystem permissions (0600, root-owned).

The public key is marshalled as a PKIX DER SubjectPublicKeyInfo structure, base64-encoded, and wrapped in a v=DKIM1; k=rsa; p=<key> DNS TXT value ready to paste into your DNS zone under <selector>._domainkey.<domain>.

bits must be 2048, 3072, or 4096. 2048 bits is the current industry standard for DKIM; 4096 produces a longer DNS TXT record that some providers may need to split across multiple 255-byte strings.

Security note: the derived DKIM key is cryptographically linked to the source Ed25519 key. Compromising either key compromises both.

type MoneroKeys

type MoneroKeys struct {
	// PrimaryAddress is the main Monero address (starts with "4")
	PrimaryAddress string
	// Subaddresses is a list of subaddresses (start with "8")
	// Index 0 is subaddress (0,1), index 1 is (0,2), etc.
	Subaddresses []string
}

MoneroKeys contains the primary address and subaddresses derived from a polyseed.

func DeriveMoneroKeys

func DeriveMoneroKeys(mnemonic string, numSubaddresses int) (*MoneroKeys, error)

DeriveMoneroKeys derives a Monero primary address and subaddresses from a polyseed mnemonic. The function decodes the polyseed to extract the seed bytes, then derives the Monero spend and view keys, and generates the requested number of subaddresses.

Parameters:

  • mnemonic: A valid 16-word polyseed mnemonic phrase
  • numSubaddresses: Number of subaddresses to generate (0 for none)

Returns:

  • MoneroKeys: Contains the primary address and subaddresses
  • error: Any error that occurred during derivation
Example
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	polyseed, err := seedify.ToMnemonicWithLength(&key, 16, "", false, seedify.PolyseedDefaultBirthday)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	keys, err := seedify.DeriveMoneroKeys(polyseed, 3)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("primary starts with 4:", keys.PrimaryAddress[:1] == "4")
	fmt.Println("subaddress count:", len(keys.Subaddresses))
}

type NostrKeys

type NostrKeys struct {
	// Npub is the public key in bech32 format (starts with "npub1")
	Npub string
	// Nsec is the private key in bech32 format (starts with "nsec1")
	Nsec string
	// PubKeyHex is the raw public key in hexadecimal format (64 characters)
	PubKeyHex string
	// PrivKeyHex is the raw private key in hexadecimal format (64 characters)
	PrivKeyHex string
}

NostrKeys contains all Nostr key formats derived from a mnemonic.

func DeriveNostrKeysWithHex

func DeriveNostrKeysWithHex(mnemonic string, bip39Passphrase string) (*NostrKeys, error)

DeriveNostrKeysWithHex derives Nostr keys from a BIP39 mnemonic phrase. Returns keys in both bech32 (npub/nsec) and hexadecimal formats. The function follows NIP-06 standard: it converts the mnemonic to a BIP39 seed, then uses BIP32 hierarchical derivation with path m/44'/1237'/0'/0/0 to derive the Nostr private key.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • NostrKeys: Contains npub, nsec, pubKeyHex, and privKeyHex
  • error: Any error that occurred during derivation
Example
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, err := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	nostrKeys, err := seedify.DeriveNostrKeysWithHex(mnemonic, "")
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("npub:", nostrKeys.Npub[:10]+"...")
	fmt.Println("nsec:", nostrKeys.Nsec[:10]+"...")
	fmt.Println("pubkey hex length:", len(nostrKeys.PubKeyHex))
	fmt.Println("privkey hex length:", len(nostrKeys.PrivKeyHex))
}

type OnionServiceKeys added in v1.20.0

type OnionServiceKeys struct {
	// OnionAddress is the 56-character v3 .onion hostname, e.g.
	// "xyz...xyz.onion". This is the public identity of the hidden service.
	OnionAddress string

	// PrivateKeyFile is the binary content to write as hs_ed25519_secret_key
	// (96 bytes: 32-byte Tor header + 64-byte expanded Ed25519 private key).
	PrivateKeyFile []byte

	// PublicKeyFile is the binary content to write as hs_ed25519_public_key
	// (64 bytes: 32-byte Tor header + 32-byte Ed25519 public key).
	PublicKeyFile []byte

	// HostnameFile is the content to write as hostname (onion address + "\n").
	HostnameFile []byte
}

OnionServiceKeys holds all the material needed to deploy a Tor v3 hidden service derived from an Ed25519 SSH key.

func DeriveOnionServiceKeys added in v1.20.0

func DeriveOnionServiceKeys(key *ed25519.PrivateKey) (*OnionServiceKeys, error)

DeriveOnionServiceKeys deterministically derives a Tor v3 hidden service identity from an Ed25519 SSH private key.

Derivation follows the same domain-separation pattern used throughout this package: a 32-byte sub-seed is produced by SHA-256("seedify:tor:v3:" || key.Seed()), then an Ed25519 sub-key is created from that sub-seed. The sub-key is independent of all other derived keys (RSA, DKIM, PGP) because each uses a distinct label.

The returned OnionServiceKeys contains:

  • OnionAddress: the 56-char v3 .onion hostname (ready to share publicly)
  • PrivateKeyFile: write to <HiddenServiceDir>/hs_ed25519_secret_key
  • PublicKeyFile: write to <HiddenServiceDir>/hs_ed25519_public_key
  • HostnameFile: write to <HiddenServiceDir>/hostname

Security note: the derived hidden service key is cryptographically linked to the source SSH key. Compromising either compromises both.

type PGPKeypair added in v1.20.0

type PGPKeypair struct {
	// PrimaryKey is the RSA private key for the OpenPGP primary key packet.
	// It carries the [SC] (Sign + Certify) usage flags.
	PrimaryKey *rsa.PrivateKey

	// EncryptSubkey is the RSA private key for the OpenPGP encryption subkey
	// packet. It carries the [E] (Encrypt) usage flag.
	EncryptSubkey *rsa.PrivateKey

	// CreationTime is the fixed seedify PGP epoch (2020-01-01 00:00:00 UTC).
	// See pgpEpoch for the rationale behind using a constant rather than a
	// hash-derived or live-clock value.
	CreationTime time.Time
}

PGPKeypair holds the two RSA keys needed to build a standard OpenPGP secret key block: a primary key used for signing and certification ([SC]), and an encryption subkey ([E]). Both are derived deterministically from the same Ed25519 source key using distinct domain-separation labels.

func DerivePGPKeypair added in v1.20.0

func DerivePGPKeypair(key *ed25519.PrivateKey, bits int) (*PGPKeypair, error)

DerivePGPKeypair deterministically derives a pair of RSA private keys from an Ed25519 private key, intended for use as an OpenPGP primary key (signing / certification) and encryption subkey.

The two keys are derived with separate domain-separation labels:

  • Primary key: "seedify:pgp:primary:" + seed
  • Encryption subkey: "seedify:pgp:encrypt:" + seed

This guarantees that the primary key and the encryption subkey are cryptographically independent, even though they share the same source.

The CreationTime field is derived deterministically from the first 4 bytes of the primary domain hash, ensuring the OpenPGP fingerprint is stable across invocations with the same source key.

bits must be 2048, 3072, or 4096. 4096 is strongly recommended.

Security note: if the source Ed25519 key is compromised, both derived RSA keys are also compromised. This is a one-way derivation.

type PayNymKeys

type PayNymKeys struct {
	// PaymentCode is the Base58Check-encoded BIP47 payment code (starts with "PM8T").
	PaymentCode string
	// NotificationAddress is the P2PKH address for receiving notification transactions.
	NotificationAddress string
}

PayNymKeys contains the BIP47 payment code (PayNym) and notification address. The payment code is derived from m/47'/0'/0'; the notification address from m/47'/0'/0'/0.

func DerivePayNym

func DerivePayNym(mnemonic string, bip39Passphrase string) (*PayNymKeys, error)

DerivePayNym derives a BIP47 payment code (PayNym) and notification address from a BIP39 mnemonic. The function follows BIP47 with derivation path m/47'/0'/0' for the payment code and m/47'/0'/0'/0 for the notification address. Uses version 1 payment code format.

Parameters:

  • mnemonic: A valid BIP39 mnemonic phrase (12, 15, 18, 21, or 24 words)
  • bip39Passphrase: Optional BIP39 passphrase (empty string if not used)

Returns:

  • PayNymKeys: The payment code and notification address
  • error: Any error that occurred during derivation
Example
package main

import (
	"crypto/ed25519"
	"fmt"

	"github.com/complex-gh/seedify"
)

// testKey returns a deterministic Ed25519 key for examples.
// In real usage this would come from an SSH key file.
func testKey() ed25519.PrivateKey {
	seed := make([]byte, ed25519.SeedSize)
	for i := range seed {
		seed[i] = byte(i + 1)
	}
	return ed25519.NewKeyFromSeed(seed)
}

func main() {
	key := testKey()

	mnemonic, _ := seedify.ToMnemonicWithLength(&key, 24, "", false, 0)

	paynym, err := seedify.DerivePayNym(mnemonic, "")
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("payment code prefix:", paynym.PaymentCode[:4])
}

Directories

Path Synopsis
cmd
seedify command
Package main provides the seedify CLI tool for generating seed phrases from SSH keys.
Package main provides the seedify CLI tool for generating seed phrases from SSH keys.
scripts
derive_zcash command
derive_zcash derives a Zcash transparent (t1) address from a BIP39 mnemonic for testing.
derive_zcash derives a Zcash transparent (t1) address from a BIP39 mnemonic for testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL