mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
LSAG ring-signature key → RingSig (descriptive, not Corona-lemur)
Two distinct concepts that shared the "Corona" name in CLI code are
now disambiguated:
1. Production R-LWE threshold signature library — was "Corona",
now Corona. Affects consensus / threshold-sign code paths,
genesis precompile entry, threshold-scheme name, NTT references.
2. LSAG ring-signature key derivation (independent feature, named
after the lemur not the threshold sig) — now `RingSig`.
Affects NewCoronaKeyBytes → NewRingSigKeyBytes,
ToCoronaPublicKey → ToRingSigPublicKey, the keyset field
`CoronaPrivateKey/PublicKey` → `RingSigPrivateKey/PublicKey`,
JSON tag `corona_private_key` → `ringsig_private_key`, and
the user-facing prose around the `lux key ring` command.
The `rt` subcommand is wired to github.com/luxfi/corona/cli (the
production library), via go.mod bump to luxfi/corona v0.2.1.
No "Corona" identifier remains in production CLI code or docs.
139 lines
4.2 KiB
Go
139 lines
4.2 KiB
Go
// Copyright (C) 2022-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package keycmd
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/luxfi/cli/pkg/key"
|
|
"github.com/luxfi/cli/pkg/prompts"
|
|
"github.com/luxfi/cli/pkg/ux"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
useMnemonic bool
|
|
mnemonicPhrase string
|
|
accountIndex uint32
|
|
)
|
|
|
|
func newCreateCmd() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "create <name>",
|
|
Short: "Create a new key set",
|
|
Long: `Create a new key set with all cryptographic key types.
|
|
|
|
Generates a BIP39 mnemonic phrase and derives:
|
|
- EC (secp256k1) key for transactions
|
|
- BLS key for consensus
|
|
- Ring-signature (LSAG) key over secp256k1
|
|
- ML-DSA key for post-quantum signatures
|
|
|
|
Keys are stored in ~/.lux/keys/<name>/
|
|
|
|
Examples:
|
|
lux key create validator1 # Generate new mnemonic
|
|
lux key create validator1 --mnemonic # Prompt for existing mnemonic
|
|
lux key create validator1 --phrase "word1 word2..." # Use provided mnemonic
|
|
lux key create mainnet-key-01 --phrase "$MNEMONIC" --account 1 # Derive account 1`,
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runCreate,
|
|
}
|
|
|
|
cmd.Flags().BoolVarP(&useMnemonic, "mnemonic", "m", false, "Import from existing mnemonic (prompts for input)")
|
|
cmd.Flags().StringVar(&mnemonicPhrase, "phrase", "", "Mnemonic phrase to import (12 or 24 words)")
|
|
cmd.Flags().Uint32Var(&accountIndex, "account", 0, "Account index for HD derivation (0-based)")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func runCreate(_ *cobra.Command, args []string) error {
|
|
name := args[0]
|
|
|
|
// Check if key set already exists
|
|
existing, err := key.ListKeySets()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list existing keys: %w", err)
|
|
}
|
|
for _, k := range existing {
|
|
if k == name {
|
|
return fmt.Errorf("key set '%s' already exists, use 'lux key delete %s' first", name, name)
|
|
}
|
|
}
|
|
|
|
var mnemonic string
|
|
|
|
switch {
|
|
case mnemonicPhrase != "":
|
|
// Use provided mnemonic
|
|
mnemonic = strings.TrimSpace(mnemonicPhrase)
|
|
if !key.ValidateMnemonic(mnemonic) {
|
|
return fmt.Errorf("invalid mnemonic phrase")
|
|
}
|
|
ux.Logger.PrintToUser("Using provided mnemonic phrase")
|
|
case useMnemonic:
|
|
// Prompt for mnemonic - requires interactive mode
|
|
if !prompts.IsInteractive() {
|
|
return fmt.Errorf("--mnemonic requires interactive mode; use --phrase to provide mnemonic directly")
|
|
}
|
|
ux.Logger.PrintToUser("Enter your 24-word mnemonic phrase:")
|
|
var err error
|
|
mnemonic, err = app.Prompt.CaptureString("Mnemonic")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mnemonic = strings.TrimSpace(mnemonic)
|
|
if !key.ValidateMnemonic(mnemonic) {
|
|
return fmt.Errorf("invalid mnemonic phrase")
|
|
}
|
|
default:
|
|
// Generate new mnemonic
|
|
var err error
|
|
mnemonic, err = key.GenerateMnemonic()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to generate mnemonic: %w", err)
|
|
}
|
|
|
|
ux.Logger.PrintToUser("")
|
|
ux.Logger.PrintToUser("Generated new mnemonic phrase (SAVE THIS SECURELY!):")
|
|
ux.Logger.PrintToUser("")
|
|
ux.Logger.PrintToUser(" %s", mnemonic)
|
|
ux.Logger.PrintToUser("")
|
|
ux.Logger.PrintToUser("WARNING: This is the ONLY time you will see this mnemonic!")
|
|
ux.Logger.PrintToUser("Store it safely - it can recover all your keys.")
|
|
ux.Logger.PrintToUser("")
|
|
}
|
|
|
|
// Derive all keys from mnemonic with account index
|
|
if accountIndex > 0 {
|
|
ux.Logger.PrintToUser("Deriving keys from mnemonic (account %d)...", accountIndex)
|
|
} else {
|
|
ux.Logger.PrintToUser("Deriving keys from mnemonic...")
|
|
}
|
|
|
|
keySet, err := key.DeriveAllKeysWithAccount(name, mnemonic, accountIndex)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to derive keys: %w", err)
|
|
}
|
|
|
|
// Save key set
|
|
if err := key.SaveKeySet(keySet); err != nil {
|
|
return fmt.Errorf("failed to save keys: %w", err)
|
|
}
|
|
|
|
ux.Logger.PrintToUser("")
|
|
ux.Logger.PrintToUser("Key set '%s' created successfully!", name)
|
|
ux.Logger.PrintToUser("")
|
|
ux.Logger.PrintToUser("Key types generated:")
|
|
ux.Logger.PrintToUser(" - EC (secp256k1): Transaction signing")
|
|
ux.Logger.PrintToUser(" - BLS: Consensus signatures")
|
|
ux.Logger.PrintToUser(" - Ring-sig (LSAG over secp256k1)")
|
|
ux.Logger.PrintToUser(" - ML-DSA: Post-quantum signatures")
|
|
ux.Logger.PrintToUser("")
|
|
ux.Logger.PrintToUser("Use 'lux key show %s' to view public keys and addresses.", name)
|
|
|
|
return nil
|
|
}
|