Lux Docs
Lux Skills Reference

Lux HSM - Unified Hardware Security Module Integration

Documentation for Lux HSM - Unified Hardware Security Module Integration

Overview

Lux HSM (github.com/luxfi/hsm) is a unified Go library for hardware security module, KMS, and custody operations across the Lux ecosystem. It provides a single entry point for password providers (symmetric KMS decrypt), signing providers (asymmetric sign/verify), post-quantum ML-DSA signatures (FIPS 204 via Cloudflare CIRCL), threshold key share storage with AES-256-GCM encryption, and HSM-attested threshold signing.

When to use

  • Adding HSM-backed signing to the MPC API server
  • Decrypting ZapDB encryption passwords via cloud KMS
  • Implementing post-quantum signing (ML-DSA-44/65/87)
  • Storing threshold key shares with hardware attestation
  • Supporting a new cloud KMS provider

Hard requirements

  1. ALWAYS use github.com/luxfi/* packages -- NEVER go-ethereum or luxfi
  2. NEVER store key shares in plaintext -- always use KeyShareVault with AES-256-GCM
  3. NEVER hardcode passwords -- use PasswordProvider interface (cloud KMS or env/file)
  4. Cloud SDK calls use raw HTTP with SigV4/OAuth -- NO AWS/GCP/Azure SDK imports
  5. LocalSigner is development only -- NEVER use in production

Quick reference

ItemValue
Modulegithub.com/luxfi/hsm
Go1.26.1
LicenseApache 2.0
Package TypeLibrary (no binary)
Only Dependencygithub.com/luxfi/crypto@v1.17.40
Transitivegithub.com/cloudflare/circl@v1.6.3 (ML-DSA)

Core Concepts

Interfaces

// Signer provides asymmetric signing and verification using HSM-backed keys.
type Signer interface {
    Sign(ctx context.Context, keyID string, message []byte) ([]byte, error)
    Verify(ctx context.Context, keyID string, message, signature []byte) (bool, error)
    Provider() string
}

// PasswordProvider retrieves or derives a decrypted password string.
type PasswordProvider interface {
    GetPassword(ctx context.Context, keyID string) (string, error)
}

Signer Providers

ProviderTypeAlgorithmFile
awsAWS KMSECDSA_SHA_256signer_aws.go
gcpGoogle Cloud KMSEC_SIGN_P256_SHA256signer_gcp.go
azureAzure Key VaultECDSA P-256signer_azure.go
zymbitZymbit SCMECDSA P-256 (PKCS#11, port 6789)signer_zymbit.go
mldsa / pq / post-quantumPost-QuantumML-DSA-44/65/87 (FIPS 204)signer_mldsa.go
local / ""In-MemoryECDSA P-256 (dev only)signer_local.go

Password Providers

ProviderTypeEnv Vars
awsAWS KMS DecryptZAPDB_ENCRYPTED_PASSWORD, MPC_HSM_KEY_ID, AWS_REGION
gcpGCP KMS DecryptZAPDB_ENCRYPTED_PASSWORD, GCP_PROJECT_ID, GCP_KMS_LOCATION, GCP_KMS_KEYRING, GCP_KMS_KEY
azureAzure Key Vault unwrapKeyZAPDB_ENCRYPTED_PASSWORD, AZURE_VAULT_URL, AZURE_KEY_NAME, AZURE_KEY_VERSION
envEnvironment VariableLUX_MPC_PASSWORD or ZAPDB_PASSWORD
fileFile Read (K8s secret)MPC_PASSWORD_FILE

Manager (Unified Entry Point)

cfg := hsm.Config{
    PasswordProvider: "aws",
    PasswordKeyID:    "arn:aws:kms:us-east-1:...",
    SignerProvider:   "aws",
    SignerKeyID:      "arn:aws:kms:us-east-1:...",
    Region:           "us-east-1",
}
mgr, err := hsm.New(cfg)

password, err := mgr.GetPassword(ctx)         // Decrypt ZapDB password
sig, err := mgr.Sign(ctx, message)             // Sign with default key
sig, err := mgr.SignWithKey(ctx, keyID, msg)   // Sign with specific key
ok, err := mgr.Verify(ctx, message, sig)       // Verify with default key

Factory Functions

// Create signer directly (no Manager overhead)
signer, err := hsm.NewSigner("mldsa", nil)
sig, err := signer.Sign(ctx, "my-key", message)

// Create password provider directly
pw, err := hsm.NewPasswordProvider("env", map[string]string{"env_var": "MY_DB_PASSWORD"})
password, err := pw.GetPassword(ctx, "")

Post-Quantum Signing (ML-DSA)

signer := hsm.NewMLDSASigner(mldsa.MLDSA65) // NIST Level 3, 192-bit PQ security
sig, err := signer.Sign(ctx, "validator-0", message)
ok, err := signer.Verify(ctx, "validator-0", message, sig)

Modes: MLDSA44 (128-bit), MLDSA65 (192-bit, recommended), MLDSA87 (256-bit).

AWS Authentication

AWS requests use SigV4 signing implemented from scratch (no AWS SDK). Credential resolution:

  1. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY + optional AWS_SESSION_TOKEN
  2. EC2 Instance Metadata Service (IMDS v2) for IAM role credentials

Threshold Integration

KeyShareVault

AES-256-GCM encrypted storage for threshold key shares:

vault := hsm.NewKeyShareVault(passwordProvider, "kms-key-id")
vault.Store(ctx, "validator-0", share.Bytes(), meta)
raw, meta, err := vault.Load(ctx, "validator-0")

HSMAttestingSigner

Wraps any threshold.Signer with HSM co-signatures for hardware binding:

signer := hsm.NewAttestingSigner(inner, hsmSigner, "attestation-key")
share, _ := signer.SignShare(ctx, message, signers, nonce)
ok, _ := hsm.VerifyAttestation(ctx, hsmSigner, "attestation-key", share)

Wire format: [4-byte share length][share bytes][attestation bytes]

ThresholdHSM Interface

For HSMs with native threshold support (Zymbit SCM, custom FPGA):

type ThresholdHSM interface {
    Signer
    NonceGen(ctx context.Context, keyID, sessionID string) (commitment []byte, nonceRef string, err error)
    SignThresholdShare(ctx context.Context, keyID, sessionID, nonceRef string, message []byte, signerIndices []int) ([]byte, error)
    ImportKeyShare(ctx context.Context, keyID string, share []byte) error
    ExportPublicShare(ctx context.Context, keyID string) ([]byte, error)
}

File Structure

hsm/
  hsm.go                    -- Package doc, consolidation overview
  signer.go                 -- Signer + PasswordProvider interfaces
  factory.go                -- NewSigner() + NewPasswordProvider() factories
  manager.go                -- Manager: unified Config + Sign/Verify/GetPassword
  auth_helpers.go           -- AWS SigV4, GCP metadata token, Azure MSI token
  password_providers.go     -- AWSKMSProvider, GCPKMSProvider, AzureKVProvider, EnvProvider, FileProvider
  signer_aws.go             -- AWS KMS signer (ECDSA_SHA_256)
  signer_gcp.go             -- GCP KMS signer (EC_SIGN_P256_SHA256)
  signer_azure.go           -- Azure Key Vault signer
  signer_zymbit.go          -- Zymbit SCM signer (local PKCS#11, port 6789)
  signer_mldsa.go           -- ML-DSA post-quantum signer (FIPS 204 via circl)
  signer_local.go           -- In-memory ECDSA P-256 (dev only)
  threshold_adapter.go      -- ThresholdHSM, KeyShareVault, HSMAttestingSigner, ThresholdManager
  threshold_adapter_test.go -- Tests for threshold integration
  hsm_test.go               -- Tests for all providers and manager

Testing

go test ./... -v

Tests cover:

  • All signer factory providers (13 cases including case/whitespace normalization)
  • Config passthrough (region, API addr)
  • Local signer sign/verify roundtrip
  • ML-DSA sign/verify roundtrip
  • Manager lifecycle (sign, verify, password)
  • Env and File password providers
  • KeyShareVault encrypt/decrypt roundtrips
  • Threshold adapter attestation and verification
  • ThresholdManager full lifecycle

Troubleshooting

IssueCauseSolution
AWS KMS 400 errorWrong key typeUse SIGN_VERIFY key (not ENCRYPT_DECRYPT) for signers
no AWS credentialsMissing env vars and not on EC2Set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY or use instance role
Zymbit timeoutDevice not connectedCheck USB/I2C connection, verify port 6789
ML-DSA key not foundKeys are per-process in-memoryKeys auto-generate per keyID, persist externally if needed
Vault decryption failKMS password changedRe-encrypt vault contents with new password
Attestation invalidWrong HSM keyVerify attestation key ID matches signing key
GCP metadata 404Not on GCE/GKEUse env/file provider locally, GCP only in cloud
Azure MSI failNo managed identityAssign system or user-assigned managed identity
unknown signer providerTypo in provider nameSupported: aws, gcp, azure, zymbit, mldsa, pq, post-quantum, local
  • lux/lux-mpc.md -- MPC wallet service (primary consumer of HSM signing)
  • lux/lux-threshold.md -- Threshold signature protocols
  • lux/lux-crypto.md -- Underlying crypto primitives (ML-DSA, ECDSA, BLS)
  • lux/lux-ledger.md -- Hardware wallet (Ledger device) integration

On this page