wallet

package
v0.1.11 Latest Latest
Warning

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

Go to latest
Published: Dec 5, 2025 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package wallet provides hierarchical deterministic (HD) wallet functionality for the Zenon Network, including BIP39 mnemonic generation, BIP32/BIP44 key derivation, and encrypted keystore management.

The wallet package enables secure storage and management of Zenon Network keypairs using industry-standard cryptographic practices. Wallets are encrypted with Argon2 key derivation and stored as JSON keyfiles.

Basic Usage

Create a new wallet with a random mnemonic:

manager, err := wallet.NewKeyStoreManager("./wallets")
if err != nil {
    log.Fatal(err)
}

// Create new wallet with password protection
keystore, err := manager.CreateNew("my-secure-password", "main-wallet")
if err != nil {
    log.Fatal(err)
}

fmt.Println("Mnemonic:", keystore.Mnemonic)
fmt.Println("Base address:", keystore.GetBaseAddress())

Key Derivation

The wallet follows BIP44 derivation path: m/44'/73404'/account'/0'/0' where 73404 is Zenon's registered coin type.

Derive keypairs at different indices:

// Get default keypair (index 0)
keypair0, err := keystore.GetKeyPair(0)
address0, _ := keypair0.GetAddress()

// Derive multiple addresses
keypair1, _ := keystore.GetKeyPair(1)
keypair2, _ := keystore.GetKeyPair(2)

Importing Existing Mnemonics

Import a wallet from an existing BIP39 mnemonic:

mnemonic := "route become dream access impulse price inform obtain engage ski believe awful"
keystore, err := manager.CreateFromMnemonic(mnemonic, "password", "imported-wallet")
if err != nil {
    log.Fatal(err)
}

Wallet Persistence

Wallets are automatically saved as encrypted keyfiles. Load an existing wallet:

keystore, err := manager.ReadKeyStore("password", "main-wallet")
if err != nil {
    log.Fatal(err)
}

// List all wallets in directory
wallets, err := manager.ListAllKeyStores()
for _, name := range wallets {
    fmt.Println("Wallet:", name)
}

Cryptographic Operations

Sign and verify messages with Ed25519:

keypair, _ := keystore.GetKeyPair(0)
message := []byte("Hello Zenon")

// Sign message
signature, err := keypair.Sign(message)
if err != nil {
    log.Fatal(err)
}

// Verify signature
valid, err := keypair.Verify(signature, message)
if err != nil || !valid {
    log.Fatal("Invalid signature")
}

Security Considerations

- Mnemonics should be backed up securely and never shared - Passwords should be strong and unique - Keyfiles are encrypted but filesystem permissions should be restricted - Never commit keyfiles to version control

For more examples, see https://pkg.go.dev/github.com/0x3639/znn-sdk-go/wallet

Example

Example demonstrates creating a new wallet with random mnemonic.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	// Create temporary directory for example
	tempDir, _ := os.MkdirTemp("", "wallet-example-*")
	defer os.RemoveAll(tempDir)

	// Create wallet manager
	manager, err := wallet.NewKeyStoreManager(tempDir)
	if err != nil {
		log.Fatal(err)
	}

	// Create new wallet with random mnemonic
	keystore, err := manager.CreateNew("secure-password", "my-wallet")
	if err != nil {
		log.Fatal(err)
	}

	// Display mnemonic (MUST be backed up securely!)
	fmt.Println("Wallet created successfully")

	// Verify mnemonic was generated
	if len(keystore.Mnemonic) > 0 {
		fmt.Println("Mnemonic generated")
	}

	// Get base address (first address, index 0)
	_, err = keystore.GetBaseAddress()
	if err == nil {
		fmt.Println("Base address derived")
	}

}
Output:

Wallet created successfully
Mnemonic generated
Base address derived
Example (BulkAddressGeneration)

Example_bulkAddressGeneration demonstrates efficient bulk address derivation.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-bulk-*")
	defer os.RemoveAll(tempDir)

	manager, _ := wallet.NewKeyStoreManager(tempDir)
	keystore, _ := manager.CreateNew("password", "bulk-wallet")

	// Derive addresses 0-4 in one call
	addresses, err := keystore.DeriveAddressesByRange(0, 5)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Generated %d addresses\n", len(addresses))
	for i, addr := range addresses {
		fmt.Printf("Address %d: %s...\n", i, addr.String()[:12])
	}
}
Example (DeriveMultipleAddresses)

Example_deriveMultipleAddresses demonstrates deriving multiple addresses from one wallet.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-derive-*")
	defer os.RemoveAll(tempDir)

	manager, _ := wallet.NewKeyStoreManager(tempDir)
	keystore, _ := manager.CreateNew("password", "multi-address-wallet")

	// Derive first 3 addresses
	for i := 0; i < 3; i++ {
		keypair, err := keystore.GetKeyPair(i)
		if err != nil {
			log.Fatal(err)
		}

		address, _ := keypair.GetAddress()
		fmt.Printf("Address %d: %s...\n", i, address.String()[:12])
	}

	// All addresses derived from same mnemonic
	fmt.Println("All addresses from single mnemonic")
}
Example (FindAddress)

Example_findAddress demonstrates searching for an address in the wallet.

package main

import (
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-find-*")
	defer os.RemoveAll(tempDir)

	manager, _ := wallet.NewKeyStoreManager(tempDir)
	keystore, _ := manager.CreateNew("password", "search-wallet")

	// Get an address to search for
	targetKeypair, _ := keystore.GetKeyPair(5)
	targetAddr, _ := targetKeypair.GetAddress()

	// Find which index this address belongs to
	result, err := keystore.FindAddress(*targetAddr, 10)
	if errors.Is(err, wallet.ErrAddressNotFound) {
		fmt.Println("Address not found")
	} else if err != nil {
		log.Fatal(err)
	} else {
		fmt.Printf("Address found at index: %d\n", result.Index)
		// Can use result.KeyPair to sign transactions
	}

}
Output:

Address found at index: 5
Example (ImportMnemonic)

Example_importMnemonic demonstrates restoring a wallet from an existing mnemonic.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-import-*")
	defer os.RemoveAll(tempDir)

	manager, err := wallet.NewKeyStoreManager(tempDir)
	if err != nil {
		log.Fatal(err)
	}

	// Import wallet from existing mnemonic
	mnemonic := "route become dream access impulse price inform obtain engage ski believe awful"
	keystore, err := manager.CreateFromMnemonic(mnemonic, "new-password", "imported-wallet")
	if err != nil {
		log.Fatal(err)
	}

	// Verify import succeeded
	baseAddr, _ := keystore.GetBaseAddress()
	fmt.Println("Wallet imported successfully")
	fmt.Printf("Address: %s...\n", baseAddr.String()[:12])

	// Same mnemonic always generates same addresses
	fmt.Println("Mnemonic restored consistently")
}
Example (ListWallets)

Example_listWallets demonstrates listing all wallets in a directory.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-list-*")
	defer os.RemoveAll(tempDir)

	manager, _ := wallet.NewKeyStoreManager(tempDir)

	// Create multiple wallets
	manager.CreateNew("password", "wallet-1")
	manager.CreateNew("password", "wallet-2")
	manager.CreateNew("password", "wallet-3")

	// List all wallets
	wallets, err := manager.ListAllKeyStores()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Found %d wallets:\n", len(wallets))
	for _, name := range wallets {
		fmt.Printf("- %s\n", name)
	}
}
Example (SaveAndLoadWallet)

Example_saveAndLoadWallet demonstrates wallet persistence.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-persist-*")
	defer os.RemoveAll(tempDir)

	manager, _ := wallet.NewKeyStoreManager(tempDir)

	// Create and save wallet
	keystore1, _ := manager.CreateNew("password123", "persistent-wallet")
	addr1, _ := keystore1.GetBaseAddress()
	fmt.Printf("Created wallet: %s...\n", addr1.String()[:12])

	// Load wallet from disk
	keystore2, err := manager.ReadKeyStore("password123", "persistent-wallet")
	if err != nil {
		log.Fatal(err)
	}
	addr2, _ := keystore2.GetBaseAddress()
	fmt.Printf("Loaded wallet: %s...\n", addr2.String()[:12])

	// Verify they match
	if addr1.String() == addr2.String() {
		fmt.Println("Wallet persisted correctly")
	}
}
Example (SignAndVerify)

Example_signAndVerify demonstrates cryptographic signing with a keypair.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/0x3639/znn-sdk-go/wallet"
)

func main() {
	tempDir, _ := os.MkdirTemp("", "wallet-sign-*")
	defer os.RemoveAll(tempDir)

	manager, _ := wallet.NewKeyStoreManager(tempDir)
	keystore, _ := manager.CreateNew("password", "signing-wallet")

	// Get keypair for signing
	keypair, _ := keystore.GetKeyPair(0)

	// Sign a message
	message := []byte("Hello Zenon Network")
	signature, err := keypair.Sign(message)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Signature length: %d bytes\n", len(signature))

	// Verify signature
	valid, err := keypair.Verify(signature, message)
	if err != nil {
		log.Fatal(err)
	}

	if valid {
		fmt.Println("Signature verified successfully")
	} else {
		fmt.Println("Signature verification failed")
	}

}
Output:

Signature length: 64 bytes
Signature verified successfully

Index

Examples

Constants

View Source
const (
	// HardenedKeyStart is the index at which hardened keys start (2^31)
	HardenedKeyStart = 0x80000000

	// Ed25519Curve is the curve name for SLIP-0010
	Ed25519Curve = "ed25519 seed"
)
View Source
const (
	// BaseAddressKey is the JSON key for the base address in wallet metadata
	BaseAddressKey = "baseAddress"

	// WalletTypeKey is the JSON key for the wallet type in wallet metadata
	WalletTypeKey = "walletType"

	// KeyStoreWalletType is the type identifier for keystore wallets
	KeyStoreWalletType = "keystore"

	// DefaultMaxIndex is the maximum address index to search
	DefaultMaxIndex = 10000
)
View Source
const (
	// CoinType is the BIP44 coin type for Zenon (73404')
	CoinType = "73404"

	// DerivationPath is the base BIP44 path for Zenon wallets
	DerivationPath = "m/44'/" + CoinType + "'"
)
View Source
const (
	// MinPasswordLength is the minimum recommended password length for wallet encryption
	MinPasswordLength = 8
)

Variables

View Source
var (
	ErrWalletManagerStopped = errors.New("wallet manager has not started")
	ErrIncorrectPassword    = errors.New("incorrect password")
	ErrInvalidMnemonic      = errors.New("invalid mnemonic")
	ErrInvalidEntropy       = errors.New("invalid entropy")
	ErrWalletNotFound       = errors.New("wallet not found")
	ErrWalletAlreadyExists  = errors.New("wallet already exists")
	ErrInvalidKeyStore      = errors.New("invalid keystore")
	ErrInvalidPrivateKey    = errors.New("invalid private key")
	ErrAddressNotFound      = errors.New("address not found in wallet")
	ErrKeystoreNotFound     = errors.New("keystore not found")
)

Common wallet errors

Functions

func DeriveKey

func DeriveKey(path string, seedHex string) ([]byte, error)

DeriveKey is a convenience function that derives a key from a path and seed and returns the Ed25519 private key

func EntropyToMnemonic

func EntropyToMnemonic(entropy []byte) (string, error)

EntropyToMnemonic converts entropy bytes to a mnemonic

func GenerateMnemonic

func GenerateMnemonic(strength int) (string, error)

GenerateMnemonic generates a BIP39 mnemonic with the given entropy strength strength must be 128, 160, 192, 224, or 256 bits 128 bits = 12 words, 256 bits = 24 words

func GeneratePublicKey

func GeneratePublicKey(privateKey []byte) ([]byte, error)

GeneratePublicKey is a static method that generates a public key from a private key

func GetDerivationAccount

func GetDerivationAccount(account int) string

GetDerivationAccount returns the BIP44 derivation path for a given account index For example: account 0 returns "m/44'/73404'/0'"

func IsValidWord

func IsValidWord(word string) bool

IsValidWord checks if a word is in the BIP39 wordlist

func MnemonicToEntropy

func MnemonicToEntropy(mnemonic string) ([]byte, error)

MnemonicToEntropy converts a mnemonic to its entropy bytes

func MnemonicToSeed

func MnemonicToSeed(mnemonic string, passphrase string) []byte

MnemonicToSeed converts a mnemonic to a seed for key derivation passphrase can be empty string

func NewWalletError

func NewWalletError(message string) error

NewWalletError creates a new wallet error

func ValidateMnemonic

func ValidateMnemonic(words []string) bool

ValidateMnemonic validates a BIP39 mnemonic phrase

func ValidateMnemonicString

func ValidateMnemonicString(mnemonic string) bool

ValidateMnemonicString validates a BIP39 mnemonic phrase from a string

func ValidatePassword added in v0.1.3

func ValidatePassword(password string) error

ValidatePassword checks if a password meets minimum security requirements.

Requirements:

  • Minimum 8 characters (configurable via MinPasswordLength)
  • At least one character from any category (to prevent all-same-char passwords)

This function returns an error if the password doesn't meet requirements. For a more detailed analysis, use AnalyzePasswordStrength.

Example:

err := ValidatePassword("mypassword123")
if err != nil {
    fmt.Println("Password too weak:", err)
}

Types

type Argon2Params

type Argon2Params struct {
	Salt string `json:"salt"` // Hex encoded
}

Argon2Params contains Argon2 key derivation parameters

type CryptoParams

type CryptoParams struct {
	Argon2Params *Argon2Params `json:"argon2Params"`
	CipherData   string        `json:"cipherData"` // Hex encoded
	CipherName   string        `json:"cipherName"` // "aes-256-gcm"
	Kdf          string        `json:"kdf"`        // "argon2.IDKey"
	Nonce        string        `json:"nonce"`      // Hex encoded
}

CryptoParams contains encryption parameters

type EncryptedFile

type EncryptedFile struct {
	Metadata  map[string]interface{} `json:",inline"`
	Crypto    *CryptoParams          `json:"crypto"`
	Timestamp int64                  `json:"timestamp"`
	Version   int                    `json:"version"`
}

EncryptedFile represents an encrypted wallet file

func Encrypt

func Encrypt(data []byte, password string, metadata map[string]interface{}) (*EncryptedFile, error)

Encrypt creates an encrypted file from data and password

func FromJSON

func FromJSON(data []byte) (*EncryptedFile, error)

FromJSON deserializes an encrypted file from JSON

func (*EncryptedFile) Decrypt

func (ef *EncryptedFile) Decrypt(password string) ([]byte, error)

Decrypt decrypts the encrypted file with the given password

func (*EncryptedFile) ToJSON

func (ef *EncryptedFile) ToJSON() ([]byte, error)

ToJSON serializes the encrypted file to JSON

type FindResponse

type FindResponse struct {
	Index   int
	KeyPair *KeyPair
}

FindResponse represents the result of finding an address in the keystore

type KeyData

type KeyData struct {
	Key       []byte // 32 bytes for Ed25519
	ChainCode []byte // 32 bytes
}

KeyData represents a BIP32 extended key (private key + chain code)

func DerivePath

func DerivePath(path string, seed []byte) (*KeyData, error)

DerivePath derives a key from a BIP44 path string like "m/44'/73404'/0'"

func GetMasterKeyFromSeed

func GetMasterKeyFromSeed(seed []byte) (*KeyData, error)

GetMasterKeyFromSeed derives the master key from a seed using SLIP-0010 This follows the SLIP-0010 specification for Ed25519

func (*KeyData) GetPublicKey

func (kd *KeyData) GetPublicKey() ([]byte, error)

GetPublicKey derives the Ed25519 public key from the key data

type KeyPair

type KeyPair struct {
	// contains filtered or unexported fields
}

KeyPair represents an Ed25519 key pair with address

func NewKeyPair

func NewKeyPair(privateKey []byte) *KeyPair

NewKeyPair creates a new KeyPair from a private key The public key and address will be derived lazily

func NewKeyPairFromSeed

func NewKeyPairFromSeed(seed []byte) (*KeyPair, error)

NewKeyPairFromSeed creates a KeyPair from a 32-byte seed

func (*KeyPair) Destroy added in v0.1.3

func (kp *KeyPair) Destroy()

Destroy securely zeros out the private key from memory This method should be called when the KeyPair is no longer needed to prevent the private key from lingering in memory.

IMPORTANT: After calling Destroy(), the KeyPair should not be used for any operations. Attempting to use it will result in undefined behavior.

Example:

kp, _ := NewKeyPairFromSeed(seed)
defer kp.Destroy()  // Ensure cleanup even if function panics
// ... use keypair for signing ...

func (*KeyPair) GetAddress

func (kp *KeyPair) GetAddress() (*types.Address, error)

GetAddress returns the Zenon address, deriving it if necessary

func (*KeyPair) GetPrivateKey

func (kp *KeyPair) GetPrivateKey() []byte

GetPrivateKey returns the private key bytes

func (*KeyPair) GetPublicKey

func (kp *KeyPair) GetPublicKey() ([]byte, error)

GetPublicKey returns the public key, deriving it if necessary

func (*KeyPair) Sign

func (kp *KeyPair) Sign(message []byte) ([]byte, error)

Sign signs a message with the private key

func (*KeyPair) Verify

func (kp *KeyPair) Verify(signature []byte, message []byte) (bool, error)

Verify verifies a signature against a message using this keypair's public key

type KeyStore

type KeyStore struct {
	Mnemonic string
	Entropy  []byte
	Seed     []byte
}

KeyStore represents a hierarchical deterministic wallet

func FromEncryptedFile

func FromEncryptedFile(ef *EncryptedFile, password string) (*KeyStore, error)

FromEncryptedFile decrypts an EncryptedFile to a KeyStore

func NewKeyStoreFromEntropy

func NewKeyStoreFromEntropy(entropy []byte) (*KeyStore, error)

NewKeyStoreFromEntropy creates a KeyStore from entropy bytes

func NewKeyStoreFromMnemonic

func NewKeyStoreFromMnemonic(mnemonic string) (*KeyStore, error)

NewKeyStoreFromMnemonic creates a KeyStore from a BIP39 mnemonic

func NewKeyStoreFromSeed

func NewKeyStoreFromSeed(seedHex string) (*KeyStore, error)

NewKeyStoreFromSeed creates a KeyStore from a seed

func NewKeyStoreRandom

func NewKeyStoreRandom() (*KeyStore, error)

NewKeyStoreRandom creates a new KeyStore with random entropy (256 bits)

func (*KeyStore) DeriveAddressesByRange

func (ks *KeyStore) DeriveAddressesByRange(left, right int) ([]*types.Address, error)

DeriveAddressesByRange derives multiple addresses efficiently in a single operation.

This is useful for:

  • Displaying multiple addresses to the user
  • Searching for addresses with specific properties
  • Generating address pools for services

The range is [left, right) - includes left, excludes right.

Parameters:

  • left: Starting account index (inclusive)
  • right: Ending account index (exclusive)

Returns a slice of addresses in order, or an error if derivation fails.

Example:

// Derive first 5 addresses (indices 0-4)
addresses, err := keystore.DeriveAddressesByRange(0, 5)
if err != nil {
    log.Fatal(err)
}

for i, addr := range addresses {
    fmt.Printf("Address %d: %s\n", i, addr)
}

Example output:

Address 0: z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7
Address 1: z1qqga8s8rkypgsg5qg2g7rp68nqh3r4lkm54tta
...

func (*KeyStore) FindAddress

func (ks *KeyStore) FindAddress(address types.Address, maxAccounts int) (*FindResponse, error)

FindAddress searches for a specific address within the keystore by trying account indices sequentially until found or maxAccounts is reached.

This is useful when you know an address belongs to this wallet but don't know which account index it uses. Common scenarios:

  • Finding the account index for an address shown in a block explorer
  • Locating which derivation path was used for a transaction
  • Verifying an address belongs to this wallet

Parameters:

  • address: The Zenon address to search for
  • maxAccounts: Maximum number of indices to check (0 uses DefaultMaxIndex)

Returns FindResponse containing the account index and keypair, or ErrAddressNotFound.

Example:

// Search for address in first 100 accounts
targetAddr := types.ParseAddressPanic("z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7")
result, err := keystore.FindAddress(targetAddr, 100)
if err == wallet.ErrAddressNotFound {
    fmt.Println("Address not found in this wallet")
} else if err != nil {
    log.Fatal(err)
} else {
    fmt.Printf("Found at index %d\n", result.Index)
    // Use result.KeyPair to sign transactions
}

Performance note: This is a linear search. If maxAccounts is large, it may take time.

func (*KeyStore) GetBaseAddress

func (ks *KeyStore) GetBaseAddress() (*types.Address, error)

GetBaseAddress returns the address at account index 0

func (*KeyStore) GetKeyPair

func (ks *KeyStore) GetKeyPair(account int) (*KeyPair, error)

GetKeyPair derives a keypair at the specified BIP44 account index.

The derivation follows BIP44 path: m/44'/73404'/account'/0'/0' where:

  • 44 is the BIP44 standard
  • 73404 is Zenon's registered coin type
  • account is the index you specify

Each account index generates a unique address from the same mnemonic/seed. This allows deriving multiple addresses from a single backup mnemonic.

Parameters:

  • account: Account index (0 for first address, 1 for second, etc.)

Returns a KeyPair that can:

  • Get the Zenon address
  • Sign transactions
  • Access public/private keys

Example:

// Get first address (index 0 - this is the default/base address)
keypair0, err := keystore.GetKeyPair(0)
if err != nil {
    log.Fatal(err)
}
addr0, _ := keypair0.GetAddress()
fmt.Println("First address:", addr0)

// Get second address (index 1)
keypair1, _ := keystore.GetKeyPair(1)
addr1, _ := keypair1.GetAddress()
fmt.Println("Second address:", addr1)

Note: GetKeyPair(0) returns the base address - the primary address for this wallet.

func (*KeyStore) ToEncryptedFile

func (ks *KeyStore) ToEncryptedFile(password string, metadata map[string]interface{}) (*EncryptedFile, error)

ToEncryptedFile encrypts the keystore to an EncryptedFile

type KeyStoreManager

type KeyStoreManager struct {
	WalletPath string
}

KeyStoreManager manages keystore files in a directory

func NewKeyStoreManager

func NewKeyStoreManager(walletPath string) (*KeyStoreManager, error)

NewKeyStoreManager creates a new keystore manager for managing encrypted wallet files in the specified directory.

The manager handles:

  • Creating new wallets with random mnemonics
  • Importing wallets from existing mnemonics
  • Saving encrypted keystore files
  • Loading encrypted keystore files
  • Listing all wallets in the directory

Parameters:

  • walletPath: Directory path where keystore files will be stored

The directory will be created with 0700 permissions if it doesn't exist, ensuring only the owner can read/write wallet files.

Returns a KeyStoreManager instance or an error if directory creation fails.

Example:

manager, err := wallet.NewKeyStoreManager("./my-wallets")
if err != nil {
    log.Fatal(err)
}

// Create a new wallet
keystore, _ := manager.CreateNew("password123", "main-wallet")
fmt.Println("Mnemonic:", keystore.Mnemonic)

func (*KeyStoreManager) CreateFromMnemonic

func (m *KeyStoreManager) CreateFromMnemonic(mnemonic, passphrase, name string) (*KeyStore, error)

CreateFromMnemonic imports a wallet from an existing BIP39 mnemonic phrase and saves it as an encrypted keystore file.

Use this method to:

  • Restore a wallet from a backup mnemonic
  • Import a wallet from another device
  • Migrate from another Zenon wallet application

The mnemonic must be a valid BIP39 phrase (12 or 24 words). The same mnemonic will always generate the same addresses.

Parameters:

  • mnemonic: Valid BIP39 mnemonic phrase (space-separated words)
  • passphrase: Password to encrypt the keystore (can be different from original)
  • name: Filename for the keystore

Returns the imported KeyStore or an error if the mnemonic is invalid.

Example:

manager, _ := wallet.NewKeyStoreManager("./wallets")
mnemonic := "route become dream access impulse price inform obtain engage ski believe awful"
keystore, err := manager.CreateFromMnemonic(mnemonic, "new-password", "imported-wallet")
if err != nil {
    log.Fatal(err)
}

// Verify it matches expected address
address, _ := keystore.GetBaseAddress()
fmt.Println("Restored address:", address)

func (*KeyStoreManager) CreateNew

func (m *KeyStoreManager) CreateNew(passphrase, name string) (*KeyStore, error)

CreateNew generates a new wallet with a random BIP39 mnemonic and saves it as an encrypted keystore file.

This is the primary method for creating new Zenon wallets. It:

  1. Generates a cryptographically secure 24-word BIP39 mnemonic
  2. Derives the master seed from the mnemonic
  3. Encrypts the keystore with the provided passphrase using Argon2
  4. Saves the encrypted keystore to a file

Parameters:

  • passphrase: Password to encrypt the keystore (must be non-empty)
  • name: Filename for the keystore (e.g., "main-wallet")

Returns the created KeyStore containing the mnemonic and seed, or an error.

IMPORTANT: The mnemonic must be securely backed up. It's the only way to recover the wallet if the keystore file is lost.

Example:

manager, _ := wallet.NewKeyStoreManager("./wallets")
keystore, err := manager.CreateNew("secure-password", "my-wallet")
if err != nil {
    log.Fatal(err)
}

// IMPORTANT: Back up this mnemonic securely!
fmt.Println("Mnemonic:", keystore.Mnemonic)
fmt.Println("Base address:", keystore.GetBaseAddress())

func (*KeyStoreManager) FindKeyStore

func (m *KeyStoreManager) FindKeyStore(name string) (string, error)

FindKeyStore searches for a keystore file by name Returns the filename if found, empty string if not found

func (*KeyStoreManager) GetKeystoreInfo

func (m *KeyStoreManager) GetKeystoreInfo(keyStoreFile string) (map[string]interface{}, error)

GetKeystoreInfo reads metadata from a keystore file without decrypting

func (*KeyStoreManager) ListAllKeyStores

func (m *KeyStoreManager) ListAllKeyStores() ([]string, error)

ListAllKeyStores returns all keystore files in the directory

func (*KeyStoreManager) ReadKeyStore

func (m *KeyStoreManager) ReadKeyStore(password string, keyStoreFile string) (*KeyStore, error)

ReadKeyStore loads and decrypts an existing keystore file from the managed directory.

This method:

  1. Reads the encrypted keystore file
  2. Parses the JSON structure
  3. Decrypts using the provided password
  4. Returns the KeyStore ready for use

Parameters:

  • password: Passphrase used when the keystore was created/saved
  • keyStoreFile: Filename of the keystore (not full path, just the name)

Returns the decrypted KeyStore or an error if:

  • File doesn't exist
  • Password is incorrect
  • File is corrupted

Example:

manager, _ := wallet.NewKeyStoreManager("./wallets")
keystore, err := manager.ReadKeyStore("my-password", "main-wallet")
if err != nil {
    log.Fatal("Failed to load wallet:", err)
}

// Use the keystore
keypair, _ := keystore.GetKeyPair(0)
address, _ := keypair.GetAddress()
fmt.Println("Address:", address)

func (*KeyStoreManager) SaveKeyStore

func (m *KeyStoreManager) SaveKeyStore(store *KeyStore, password, name string) error

SaveKeyStore encrypts a keystore and saves it to a file in the managed directory.

The keystore is encrypted using Argon2 key derivation with the provided password. The file is saved with 0600 permissions (readable/writable only by owner).

Parameters:

  • store: KeyStore instance to save
  • password: Passphrase for encryption (must be non-empty)
  • name: Filename for the keystore

Returns an error if encryption or file writing fails.

Example:

// Create keystore in memory
keystore, _ := wallet.NewKeyStoreRandom()

// Save to file
manager, _ := wallet.NewKeyStoreManager("./wallets")
err := manager.SaveKeyStore(keystore, "secure-password", "backup-wallet")
if err != nil {
    log.Fatal(err)
}

type PasswordStrength added in v0.1.3

type PasswordStrength int

PasswordStrength represents the strength level of a password

const (
	// PasswordWeak indicates a password that doesn't meet minimum requirements
	PasswordWeak PasswordStrength = iota
	// PasswordModerate indicates a password that meets basic requirements
	PasswordModerate
	// PasswordStrong indicates a password with good character diversity
	PasswordStrong
	// PasswordVeryStrong indicates a password with excellent character diversity
	PasswordVeryStrong
)

func AnalyzePasswordStrength added in v0.1.3

func AnalyzePasswordStrength(password string) PasswordStrength

AnalyzePasswordStrength provides a detailed analysis of password strength.

Strength scoring:

  • Weak: < 8 chars OR all same character
  • Moderate: >= 8 chars with one character class (e.g., all lowercase)
  • Strong: >= 8 chars with two character classes (e.g., letters + numbers)
  • Very Strong: >= 12 chars with three or more character classes

Character classes considered:

  • Lowercase letters (a-z)
  • Uppercase letters (A-Z)
  • Digits (0-9)
  • Special characters (punctuation, symbols, spaces)

Returns the strength level. Use ValidatePassword for simple pass/fail checking.

Example:

strength := AnalyzePasswordStrength("MyP@ssw0rd123")
fmt.Println("Strength:", strength.String())  // Output: "Very Strong"

func (PasswordStrength) String added in v0.1.3

func (s PasswordStrength) String() string

String returns the string representation of PasswordStrength

type WalletError

type WalletError struct {
	Message string
}

WalletError represents a wallet-related error

func (*WalletError) Error

func (e *WalletError) Error() string

Jump to

Keyboard shortcuts

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