Files
zeekay 65f575285e cli: rename Corona → Corona (production R-LWE threshold);
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.
2026-05-12 09:07:44 -07:00

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
}