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
- ALWAYS use
github.com/luxfi/*packages -- NEVERgo-ethereumorluxfi - NEVER store key shares in plaintext -- always use
KeyShareVaultwith AES-256-GCM - NEVER hardcode passwords -- use PasswordProvider interface (cloud KMS or env/file)
- Cloud SDK calls use raw HTTP with SigV4/OAuth -- NO AWS/GCP/Azure SDK imports
LocalSigneris development only -- NEVER use in production
Quick reference
| Item | Value |
|---|---|
| Module | github.com/luxfi/hsm |
| Go | 1.26.1 |
| License | Apache 2.0 |
| Package Type | Library (no binary) |
| Only Dependency | github.com/luxfi/crypto@v1.17.40 |
| Transitive | github.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
| Provider | Type | Algorithm | File |
|---|---|---|---|
aws | AWS KMS | ECDSA_SHA_256 | signer_aws.go |
gcp | Google Cloud KMS | EC_SIGN_P256_SHA256 | signer_gcp.go |
azure | Azure Key Vault | ECDSA P-256 | signer_azure.go |
zymbit | Zymbit SCM | ECDSA P-256 (PKCS#11, port 6789) | signer_zymbit.go |
mldsa / pq / post-quantum | Post-Quantum | ML-DSA-44/65/87 (FIPS 204) | signer_mldsa.go |
local / "" | In-Memory | ECDSA P-256 (dev only) | signer_local.go |
Password Providers
| Provider | Type | Env Vars |
|---|---|---|
aws | AWS KMS Decrypt | ZAPDB_ENCRYPTED_PASSWORD, MPC_HSM_KEY_ID, AWS_REGION |
gcp | GCP KMS Decrypt | ZAPDB_ENCRYPTED_PASSWORD, GCP_PROJECT_ID, GCP_KMS_LOCATION, GCP_KMS_KEYRING, GCP_KMS_KEY |
azure | Azure Key Vault unwrapKey | ZAPDB_ENCRYPTED_PASSWORD, AZURE_VAULT_URL, AZURE_KEY_NAME, AZURE_KEY_VERSION |
env | Environment Variable | LUX_MPC_PASSWORD or ZAPDB_PASSWORD |
file | File 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 keyFactory 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:
AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEY+ optionalAWS_SESSION_TOKEN- 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 managerTesting
go test ./... -vTests 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
| Issue | Cause | Solution |
|---|---|---|
| AWS KMS 400 error | Wrong key type | Use SIGN_VERIFY key (not ENCRYPT_DECRYPT) for signers |
no AWS credentials | Missing env vars and not on EC2 | Set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY or use instance role |
| Zymbit timeout | Device not connected | Check USB/I2C connection, verify port 6789 |
| ML-DSA key not found | Keys are per-process in-memory | Keys auto-generate per keyID, persist externally if needed |
| Vault decryption fail | KMS password changed | Re-encrypt vault contents with new password |
| Attestation invalid | Wrong HSM key | Verify attestation key ID matches signing key |
| GCP metadata 404 | Not on GCE/GKE | Use env/file provider locally, GCP only in cloud |
| Azure MSI fail | No managed identity | Assign system or user-assigned managed identity |
unknown signer provider | Typo in provider name | Supported: aws, gcp, azure, zymbit, mldsa, pq, post-quantum, local |
Related Skills
lux/lux-mpc.md-- MPC wallet service (primary consumer of HSM signing)lux/lux-threshold.md-- Threshold signature protocolslux/lux-crypto.md-- Underlying crypto primitives (ML-DSA, ECDSA, BLS)lux/lux-ledger.md-- Hardware wallet (Ledger device) integration