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 ¶
- Constants
- func BraveSync25thWord() (string, error)
- func BraveSync25thWordForDate(date time.Time) (string, error)
- func DeriveBitcoinAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveBitcoinAddressNativeSegwit(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveBitcoinAddressNativeSegwitAtIndex(mnemonic string, bip39Passphrase string, addressIndex uint32) (string, error)
- func DeriveBitcoinAddressSegwit(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveBitcoinMasterFingerprint(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveCosmosAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveDogecoinAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveEd25519KeyFromRSA(key *rsa.PrivateKey) (ed25519.PrivateKey, error)
- func DeriveEthereumAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveLitecoinAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveMoneroAddress(mnemonic string) (string, error)
- func DeriveMoneroSubaddressAtIndex(mnemonic string, index uint32) (string, error)
- func DeriveNobleAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveNostrKeys(mnemonic string, bip39Passphrase string) (npub string, nsec string, err error)
- func DeriveNostrKeysFromEd25519(key *ed25519.PrivateKey) (npub string, nsec string, err error)
- func DeriveNostrKeysFromRSA(key *rsa.PrivateKey) (npub string, nsec string, err error)
- func DeriveRSAKeyFromEd25519(key *ed25519.PrivateKey, bits int) (*rsa.PrivateKey, error)
- func DeriveRippleAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveSilentPaymentAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveSolanaAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveStellarAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveSuiAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveTronAddress(mnemonic string, bip39Passphrase string) (string, error)
- func DeriveZcashAddress(mnemonic string, bip39Passphrase string) (string, error)
- func RSASeedBytes(key *rsa.PrivateKey) ([]byte, error)
- func ToMnemonicWithBraveSync(key *ed25519.PrivateKey, seedPassphrase string) (string, error)
- func ToMnemonicWithBraveSyncFromRSA(key *rsa.PrivateKey, seedPassphrase string) (string, error)
- func ToMnemonicWithLength(key *ed25519.PrivateKey, wordCount int, seedPassphrase string, brave bool, ...) (string, error)
- func ToMnemonicWithLengthFromRSA(key *rsa.PrivateKey, wordCount int, seedPassphrase string, brave bool, ...) (string, error)
- func ToMnemonicWithPrefix(key *ed25519.PrivateKey, wordCount int, seedPassphrase string, prefix string, ...) (string, error)
- func ToMnemonicWithPrefixFromRSA(key *rsa.PrivateKey, wordCount int, seedPassphrase string, prefix string, ...) (string, error)
- type BitcoinExtendedKeys
- func DeriveBitcoinLegacyExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)
- func DeriveBitcoinMasterExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)
- func DeriveBitcoinMultisigLegacyExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)
- func DeriveBitcoinNativeSegwitExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)
- func DeriveBitcoinSegwitExtendedKeys(mnemonic string, bip39Passphrase string) (*BitcoinExtendedKeys, error)
- type BitcoinKeys
- func DeriveBitcoinLegacyKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)
- func DeriveBitcoinMultisigLegacyKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)
- func DeriveBitcoinMultisigNativeSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)
- func DeriveBitcoinMultisigSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)
- func DeriveBitcoinNativeSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)
- func DeriveBitcoinSegwitKeys(mnemonic string, bip39Passphrase string) (*BitcoinKeys, error)
- type BitcoinMultisigExtendedKeys
- type DKIMKeypair
- type MoneroKeys
- type NostrKeys
- type OnionServiceKeys
- type PGPKeypair
- type PayNymKeys
Examples ¶
Constants ¶
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 ¶
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 ¶
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 ¶
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 ¶
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")
}
Output:
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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))
}
Output:
func DeriveLitecoinAddress ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
}
Output:
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)
}
Output:
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)
}
Output:
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 ¶
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 ¶
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))
}
Output:
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 ¶
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))
}
Output:
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])
}
Output:
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. |