I've been thinking back on the conversation in #34, and I think I've found a best-of-both-worlds approach. To recap, the suggestion in #34 was to allocate a new buffer and instantiate a new Mac on each call to generateOneTimePassword to avoid synchronization, leading to higher throughput. The problem was that instantiating a new Mac was pretty slow.
It turns out that cloning a Mac is actually pretty fast, though! We can't guarantee that cloning a Mac will be possible in all setups—some provider might have a non-cloneable HmacSHA512 implementation, for example—but it'll probably be true in most setups. This lets us make generateOneTimePassword non-synchronized while still retaining thread safety, which seems like a win.
This may come at the cost of a modest throughput decrease in the single-threaded case, but if it does, it's on the order of 1%, and I'd say that's a worthwhile price to pay.
I've been thinking back on the conversation in #34, and I think I've found a best-of-both-worlds approach. To recap, the suggestion in #34 was to allocate a new buffer and instantiate a new
Mac
on each call togenerateOneTimePassword
to avoid synchronization, leading to higher throughput. The problem was that instantiating a newMac
was pretty slow.It turns out that cloning a
Mac
is actually pretty fast, though! We can't guarantee that cloning aMac
will be possible in all setups—some provider might have a non-cloneableHmacSHA512
implementation, for example—but it'll probably be true in most setups. This lets us makegenerateOneTimePassword
non-synchronized while still retaining thread safety, which seems like a win.This may come at the cost of a modest throughput decrease in the single-threaded case, but if it does, it's on the order of 1%, and I'd say that's a worthwhile price to pay.