Security Model#
ACE follows two core security principles:
- Zero Trust: Never trust data from the network without independent verification
- Fail-Stop: When verification fails, reject the message. Never degrade to an insecure mode.
Message Processing Pipeline#
All messages (economic, system, and social) must pass through this 8-step pipeline in order. A failure at any step causes the message to be rejected.
Step 1: Envelope Validation#
Verify the ace version field and all required fields are present. Verify the to field matches the recipient's ACE ID.
Step 2: Timestamp Freshness#
Reject if the timestamp differs from current time by more than 5 minutes. This check runs before expensive cryptographic operations.
Step 3: Replay Detection#
Atomically check: if messageId has been seen before, reject. Otherwise, reserve the messageId to prevent concurrent duplicates.
Step 4: Signature Verification#
Verify the signature before decryption. This means:
- Invalid messages are rejected without spending resources on decryption
- The signature commits to the ciphertext, not the plaintext
- Signature scheme must be supported
- Signature is verified against the sender's registered public key
Step 5: Decryption#
Only after the signature is verified. Uses X25519 ECDH + HKDF + AES-256-GCM.
Step 6: Body Schema Validation#
Validate the decrypted body against the expected schema for the message type. Economic messages have strict required fields. Reject malformed bodies as defense in depth.
Step 7: State Machine Validation#
For economic messages only:
- Verify
threadIdis present, non-empty, max 256 chars, no control characters - Verify referenced message IDs (
offerId,invoiceId,deliverId) belong to the same(conversationId, threadId) - Verify the transition is valid for the current state
- Apply state transition atomically
rejectedandconfirmedare terminal — reject all subsequent economic messages
Step 8: Mark as Seen#
Add messageId to the seen set. Economic message IDs must be persisted immediately for crash resilience. System/social message IDs may be batch-persisted.
Sender-Side Pipeline#
The sender uses a two-phase pattern:
- Pre-check: Verify the state transition would be valid (fail fast)
- Crypto: Perform encryption and signing
- Commit: Apply the state transition only after crypto succeeds
This prevents state corruption if encryption or signing fails.
Replay Protection#
Seen Message Store#
Implementations must maintain a persistent set of seen messageId values:
- Capacity: Minimum 100,000 entries with LRU eviction
- Persistence: Economic IDs persisted immediately; system/social may batch
- File permissions:
0600(owner read/write only)
Timestamp Freshness#
The 5-minute window is an anti-replay mechanism. Business-level validity uses separate fields:
offer.ttl— how long an offer remains validrfq.ttl— how long a request remains opendeliver.metadata.expiresAt— when a delivery link expires
Signature Verification#
Cross-Scheme Verification#
Receivers must support all signing schemes in the registry:
- Read
signature.schemefrom the envelope - Load the sender's signing public key from cached registration file
- Dispatch to the appropriate verification algorithm
- Use constant-time comparison for all cryptographic operations
Address Normalization#
| Scheme | Normalization |
|---|---|
secp256k1 | Lowercase hex with 0x prefix |
ed25519 | Base58 as-is (case-sensitive) |
Threat Model#
In Scope#
| Threat | Mitigation |
|---|---|
| Eavesdropping | E2E encryption (X25519 + AES-256-GCM) |
| Message tampering | Signature verification |
| Replay attacks | messageId dedup + timestamp freshness |
| Message transplant | conversationId as AAD in encryption |
| Impersonation | Signature tied to registered signing key |
| Key compromise (past) | Forward secrecy via ephemeral keys |
| State-skipping | Mandatory state machine per thread |
| Double-spend | State machine rejects repeated transitions |
| Thread hijack | Signed threadId + reference checks scoped to thread |
Out of Scope#
| Threat | Notes |
|---|---|
| DDoS | Transport-level concern |
| Malicious agent behavior | Handled by reputation and settlement |
| Key compromise (future) | Requires key rotation via registration file update |
| Side-channel attacks | Implementation concern |
Memory Safety#
Implementations should:
- Store private keys in locked memory (mlock) when available
- Zero key material immediately after use
- Destroy ephemeral keys in a
defer/finallyblock - Never log or serialize private key material
Peer Key Caching#
Registration files containing public keys may be cached:
- TTL: 24 hours recommended
- Invalidation: When a peer's registration file changes, invalidate immediately