Reuse initialised AES-GCM contexts for ledger encryption
- Dominant language
- C++
- Stars
- 876
- Forks
- 260
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 157
Description
## Background
A `perf` profile of the 3,000,000-request `pi_basic` workload attributes approximately:
- 24.06% inclusive CPU to `CommittableTx::serialise()`
- 9.50% inclusive CPU to AES-GCM encryption
- 6.06% inclusive CPU to the AES EVP/provider initialisation path
- 0.97% inclusive CPU to AES context allocation/free/reset
`KeyAesGcm_OpenSSL` retains the raw key and an `EVP_CIPHER*`, but each `encrypt()`/`decrypt()` creates a new `EVP_CIPHER_CTX` and fully initialises the provider and key again.
A standalone microbenchmark forced through `symcryptprovider` produced identical ciphertext and GCM tags while reducing 64-byte encryption from 873.5 ns/op to 228.9 ns/op (3.82x) by retaining keyed context state and reinitialising only with the next unique IV.
## Proposed implementation
- Make each `KeyAesGcm_OpenSSL` own a small set of pre-keyed encryption contexts, one per active CCF worker thread (or an equivalent bounded pool).
- Keep encryption and decryption contexts separate.
- Fully initialise each context once for its key/provider, then begin each operation with IV-only reinitialisation (`EVP_EncryptInit_ex2(ctx, nullptr, nullptr, iv, nullptr)` or the equivalent decrypt call).
- Continue deriving unique GCM IVs from transaction view/seqno/type exactly as today.
- Explicitly fetch and own the provider cipher once per key if this avoids implicit provider lookup while preserving configured provider selection.
- Ensure context ownership remains with the key object, rather than an unbounded `thread_local` map, so rollback/rekey destruction releases and cleanses all expanded key state.
- Avoid a single shared mutable context: ledger key objects are used concurrently by multiple enclave workers.
## Correctness and security coverage
Add tests for:
- Byte-for-byte equivalence with the existing fresh-context path.
- Concurrent encrypt/decrypt on multiple workers.
- Rekeying and switching between current and historical ledger secrets.
- Rollback removing a key and its cached contexts.
- Context recovery after a failed authenticated decryption.
- Empty plaintext/AAD combinations supported by the current API.
- Default and SymCrypt provider configurations.
Measure the change independently with the existing crypto benchmarks and an A/B `pi_basic` run/profile.
## Out of scope
Commit-evidence HMAC also appears in the profile (6.68% inclusive), but only about 1.47% is currently attributable to HMAC initialisation/context allocation. Track it only if a focused benchmark demonstrates a worthwhile end-to-end gain after the AES-GCM work.
Contributor guide
Assessment
This issue has not been assessed yet.