Secure multi-chain wallet signing service using AWS Nitro Enclaves with KMS attestation-based key protection.
Text version (ASCII)
┌─────────────────────────────────────────────────────────────────────┐
│ EC2 Instance (m7i.xlarge) │
│ │
│ ┌─────────────────────────┐ ┌────────────────────────────┐ │
│ │ Parent Process │ vsock │ Enclave │ │
│ │ │ ══════> │ │ │
│ │ • Read ciphertext from │ :5000 │ ┌──────────────────────┐ │ │
│ │ DynamoDB │ ──────> │ │ C++ Signing Service │ │ │
│ │ • Fetch IAM temp creds │ │ │ • ECDSA (EVM) │ │ │
│ │ • Send sign requests │ │ │ • Schnorr (Bitcoin) │ │ │
│ │ │ │ │ • Ed25519 (Solana) │ │ │
│ └─────────────────────────┘ │ │ • BLS (Beacon) │ │ │
│ │ └──────────────────────┘ │ │
│ ┌─────────────────────────┐ │ │ │
│ │ vsock-proxy │ │ ┌──────────────────────┐ │ │
│ │ (port 8000) │ <────── │ │ kmstool_enclave_cli │ │ │
│ │ │ │ vsock │ │ • KMS Decrypt │ │ │
│ │ ▼ │ :8000 │ │ • NSM attestation │ │ │
│ │ kms.amazonaws.com:443 │ │ └──────────────────────┘ │ │
│ └─────────────────────────┘ └────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│ ▲
▼ │
┌──────────────────┐ ┌─────────────────┐
│ DynamoDB │ │ AWS KMS │
│ (encrypted keys) │ │ (PCR0 policy) │
└──────────────────┘ └─────────────────┘
Security: Private keys never leave enclave memory. KMS only decrypts when attestation (PCR0) matches.
| Type | Algorithm | Curve | Chains |
|---|---|---|---|
| evm | ECDSA | secp256k1 | Ethereum, BSC, Polygon, Arbitrum, Avalanche |
| bitcoin | Schnorr (BIP-340) | secp256k1 | Bitcoin (Taproot) |
| solana | EdDSA | Ed25519 | Solana, Aptos, Sui, TON, Cosmos |
| beacon | BLS | BLS12-381 | Ethereum Beacon Chain (validators) |
- AWS CLI with configured credential
- Terraform >= 1.0
- SSH client
# Provision AWS infra + store test keys + generate .env
# --profile defaults to "default", --region to ap-northeast-1
./setup.sh --profile <your-aws-profile> --region <aws-region>
# Build kmstool (first time) + EIF + update KMS policy
./deploy.sh
# Start vsock-proxy + enclave
./start.sh
# KMS attestation decrypt → sign
./test.sh evm
./test.sh all # Test all chains
# Benchmark (dev/debug, plaintext key)
./test_signing.sh --bench├── enclave/
│ ├── main.cpp # Enclave: multi-chain signer + KMS decrypt_and_init
│ └── CMakeLists.txt # Build: libsecp256k1 + libsodium + blst
├── parent/
│ └── main.cpp # Parent: signing client + benchmark
├── infra/
│ └── main.tf # Terraform: VPC, EC2, KMS, DDB, IAM (tfvars auto-generated by setup.sh)
├── Dockerfile.enclave # Enclave image (C++ signer + kmstool)
├── setup.sh # Provision infra + store test keys + generate .env
├── deploy.sh # Build kmstool + EIF + update KMS policy
├── start.sh # Start vsock-proxy + enclave
├── test.sh # Production test: KMS decrypt → sign (per chain)
└── test_signing.sh # Dev test: multi-chain signing + benchmark
Tested on m7i.xlarge (4 vCPU, 16 GiB), enclave 2 vCPU / 1024 MiB, ap-northeast-1.
| Chain | Total | KMS Decrypt | Sign P50 | Sign P99 | TPS |
|---|---|---|---|---|---|
| EVM (ECDSA) | ~316ms | ~315ms | 251us | 285us | 3968 |
| Bitcoin (Schnorr) | ~306ms | ~305ms | 254us | 279us | 3906 |
| Solana (Ed25519) | ~188ms | ~187ms | 253us | 287us | 3831 |
| Beacon (BLS) | ~211ms | ~210ms | 607us | 666us | 1644 |
- KMS Decrypt: network round-trip, one-time if key cached in enclave memory
- Sign P50/P99: 1000 iterations with 50 warmup (
test_signing.sh --bench) - vsock overhead: ~200us per request, included in Sign latency
KMS pricing (ap-northeast-1): $0.03 per 10,000 symmetric requests + $1/month per key.
| Strategy | KMS calls | Cost (1M signs/month) | Latency | Security |
|---|---|---|---|---|
| Decrypt per sign | 1M | $3.00 | ~300ms | Highest |
| Decrypt on enclave start | 1 | ~$0 | ~250µs | High (enclave memory is isolated) |
| Decrypt periodically (e.g. 5min) | ~8,640 | ~$0.03 | ~250µs | High |
Recommended: decrypt on enclave start — enclave memory cannot be accessed externally, so key-in-memory is safe. Re-decrypt only on enclave restart or key rotation.
terraform -chdir=infra destroy -auto-approve