Skip to content

perf: reuse one Mac per HKDF instance - #2193

Open
sharmabikram wants to merge 1 commit into
masterfrom
shbikram/hkdf-reuse-mac
Open

sharmabikram wants to merge 1 commit into
masterfrom
shbikram/hkdf-reuse-mac

Conversation

@sharmabikram

Copy link
Copy Markdown

Issue #, if available:

Description of changes:

Why
Every message that uses an HKDF or key committing algorithm suite creates several Mac objects just to derive its keys. With the default committing suite that is four per message. Creating a Mac has a real cost on small payloads, as reported in #2174.

What this PR does

  1. HmacKeyDerivationFunction creates one Mac when the instance is made.
  2. The extract step and every deriveKey call reuse that Mac. Each step calls init() with its own key first, which resets the Mac.
  3. init and deriveKey are synchronized, so sharing one instance across threads is still safe.

The public API does not change, and nothing is cached between instances. A provider registered later is still picked up.

What to review

  • HmacKeyDerivationFunction.java: check that each use of the Mac is preceded by init() with the right key.

Testing

  • The RFC 5869 test vectors and CommittedKeyTest pass.
  • A new test checks that reusing one instance, including calling init again, gives the same keys as fresh instances.
  • A local benchmark shows CommittedKey.generate about 3% faster with the default SunJCE provider.

Thanks to @mkeskells for finding this in #2174.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Check any applicable:

  • Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files.

@sharmabikram
sharmabikram requested a review from a team as a code owner November 3, 2026 03:13
@mkeskells

Copy link
Copy Markdown

Hi @sharmabikram
From memory I think that this doesn't address the underlying problem. The expensive call is to Mac.getInstance when specifying the String algorith, and not the provider. If you provide the algorithm and the provider is much faster. This ignores the comments in the code about test validation of the supplied arguments. Thats why in my pr they are validated, and typesafe thoughout the codebase.
We could go further and provide a small cache but I didn't want to do that as its an orthogonal optimisation.

In performance test the 2 calls to getInstance (for the Mac in #2174 and Cypher in #2175) account for 45% of the CPU in our production based test cases. Clearly the test basis is likely different but we should at least compare notes on the optimistions available.

I cant share the original test cases, but I am happy to work on a clean test case that we can use to benchmark

There is write access available to the original PR. I would hope that we could build a full solution rather than extracting bits of one PR and making another

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants