void key_expand(void *dst, const void *src, u64 effort);
dst is the 256bit output key to be generated,
src is the 256bit input key,
effort is an opaque parameter that somehow tunes the
effort.The effort parameter is technically not necessary, but can be used to tune runtime to take roughly 100ms. See rationale.
As a somewhat simplistic model, I will use gate-cycles as the currency we are trying to maximize. Any 2-input boolean function (and, or, xor, etc) is considered a gate. Occupying one such function for one cycle costs a gate-cycle. Memory can be translated into gates, I think 6 gates for 1 bit of memory might be a reasonable conversion factor.
For security, this function should have all the attributes of a cryptographic hash function. If there is no faster way to find collisions or determine the input based on the output than brute force, the candidate is considered barely secure.
For me personally, a 1s delay is long enough to be a serious annoyance, a 100ms delay is fast enough to be almost imperceptible. So I will arbitrarily make a 100ms threshold the target. Equally arbitrarily I will set CPU frequency to 1GHz. So we have 100M cycles available to turn one 256bit key into another 256bit key.