Tenzro Testnet is live. Get testnet TNZO

Key Custody

Tenzro provides institutional-grade key custody through MPC threshold wallets, encrypted keystores, and hardware-backed TEE key sealing. Every identity on the network — human or machine — receives an auto-provisioned 2-of-3 MPC wallet with no seed phrases required. Keys are protected at rest with Argon2id KDF and AES-256-GCM encryption, and in computation with TEE enclave sealing.

MPC Wallet Architecture

┌──────────────────────────────────────────────┐
              MPC Wallet (2-of-3)              
                                               
  Share 1: User device (encrypted keystore)    
  Share 2: TEE enclave (hardware-sealed)       
  Share 3: Recovery backup (offline/custodian)  
                                               
  Any 2 shares can reconstruct the signing key 
  No single party ever holds the full key      
└──────────────────────────────────────────────┘

Signing flow:
  1. User initiates tx on device (Share 1)
  2. TEE enclave co-signs (Share 2)
  3. Partial signatures combined  valid signature
  4. Share 3 never touched unless recovery needed

The wallet uses Shamir Secret Sharing over GF(256) to split keys into 3 shares. The threshold is configurable but defaults to 2-of-3. Signing produces partial signatures from any 2 shares which are combined into a full Ed25519 or Secp256k1 signature.

Encrypted Keystore

Key shares stored on the user's device are protected with a password-derived encryption key using industry-standard parameters:

ParameterValuePurpose
KDFArgon2idMemory-hard password hashing (resistant to GPU/ASIC attacks)
Memory64 MBMemory cost per hash computation
Iterations3Time cost (passes over memory)
Parallelism4Degree of parallelism
CipherAES-256-GCMAuthenticated encryption of key material
Nonce12 bytes (random)Generated from CSPRNG (OsRng)
use tenzro_wallet::{WalletService, KeystoreConfig};

// Create a new MPC wallet with encrypted keystore
let wallet = WalletService::create_wallet(KeystoreConfig {
    password: "user-password",
    threshold: 2,
    total_shares: 3,
    key_type: KeyType::Ed25519,
})?;

println!("Address: {}", wallet.address());

// The keystore file is encrypted at rest:
// password → Argon2id(64MB, 3 iterations, p=4) → 256-bit key
// key + random nonce → AES-256-GCM(key_share) → ciphertext
// Stored as JSON: { version, kdf_params, cipher, ciphertext, nonce, tag }

// Import from encrypted keystore
let imported = WalletService::import_keystore(
    "/path/to/keystore.json",
    "user-password",
)?;

Key Rotation

Key shares can be rotated without changing the wallet address. During rotation, new shares are generated and distributed while the old shares are securely zeroized. The underlying public key and address remain the same.

// Rotate key shares (requires 2-of-3 current shares)
wallet.rotate_shares(
    &[current_share_1, current_share_2],
    "new-password",  // Re-encrypt with new password
)?;

// Old shares are zeroized in memory via the zeroize crate
// New shares distributed to the same locations

Spending Limits

Wallets enforce configurable spending limits through the TDIP delegation scope. Machine identities (AI agents) always have spending limits set by their human controller.

# Set spending limits via delegation scope
curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_setDelegationScope",
    "params": [{
      "did": "did:tenzro:machine:controller123:agent456",
      "max_transaction_value": "1000000000000000000",
      "max_daily_spend": "10000000000000000000",
      "allowed_operations": ["transfer", "inference"],
      "time_bound": {
        "start": "2026-01-01T00:00:00Z",
        "end": "2027-01-01T00:00:00Z"
      }
    }],
    "id": 1
  }'

Session Keys

Session keys are temporary signing keys with limited permissions and expiration. They allow dApps and agents to sign transactions without accessing the master wallet. Session keys are implemented through the ERC-4337 account abstraction module.

import { TenzroClient } from "@tenzro/sdk";

const client = new TenzroClient("https://rpc.tenzro.network");

// Create a session key with limited permissions
const session = await client.wallet.createSessionKey({
  permissions: ["transfer", "inference"],
  maxTransactionValue: "1000000000000000000", // 1 TNZO
  expiresIn: 3600, // 1 hour
  allowedContracts: ["0xmodel_registry..."],
});

console.log("Session key:", session.publicKey);
console.log("Expires:", session.expiresAt);

// Use session key to sign transactions
const tx = await client.wallet.sendWithSessionKey(session.key, {
  to: "0xrecipient...",
  value: "500000000000000000", // 0.5 TNZO
});

TEE Key Sealing

Hardware-sealed keys — On nodes with TEE hardware (Intel TDX, AMD SEV-SNP, AWS Nitro), key shares are sealed using the enclave's hardware key. Sealed data can only be decrypted inside the same enclave with the same measurement. The sealing uses AES-256-GCM with keys derived via HKDF-SHA256(key_id, vendor_tag) with domain separation per TEE vendor. See TEE Attestation for details.

CLI Usage

# Create a new wallet
tenzro-cli wallet create

# Import from keystore
tenzro-cli wallet import --keystore /path/to/keystore.json

# Check balance
tenzro-cli wallet balance

# Send transaction (requires password to decrypt keystore)
tenzro-cli wallet send --to 0xrecipient... --amount 10.0

# List wallets
tenzro-cli wallet list

Key Zeroization

All sensitive key material is zeroized on drop using the zeroize crate. This ensures private keys, key shares, and decrypted keystore contents are wiped from memory as soon as they go out of scope, preventing recovery from memory dumps.