[1]: https://developer.arm.com/documentation/ddi0601/2020-12/AArc...
[2]: https://www.intel.com/content/www/us/en/developer/articles/t...
But yes, that may mean the language can’t be implemented well on lots of modern hardware.
A lot probably can be done by avoiding some instructions, flushing caches very often, clearing branch prediction history (if possible), etc.
That would not make the language win performance shootouts, though.
There also is the problem that not all cores may be equal and that quite a few modern CPUs drop speed ‘at will’, depending on system load, core temperature, etc.
Would you have any links to more reading on this and when it happens? It's the first time I've heard it.
Regardless, you probably don't want to do your fast-path cryptography on the slowest coprocessors imaginable.
I think there are more 8-bit μCs around than ever before, even though it's harder and harder to justify using one instead of a 32-bit μC. But lots of 32-bit μCs don't have caching either, or they have it to the extent of "you can run code from internal RAM, or more slowly from internal Flash, or much more slowly from QSPI-connected memory". But that doesn't introduce any nondeterminism into the timing, because your code has control over where it's running from.
The way old processors used to do XIP with constant random access latency is pretty much dead at this point for new designs. Semiengineering did a good article on this awhile back [1]. Even if there weren't usually a lot of invisible caching in the middle, flash cells usually don't have identical access latencies (worse, they change with age/write cycles!), and the AVR conditonal branch has data-dependent timings besides. At the design side, there's also a lot of decisions like burst modes that can introduce timing variations that can change with minor design revisions. Most of these aren't documented or even well understood by manufacturers. Truly eliminating architectural timing side channels is very, very difficult today.
[1] https://semiengineering.com/what-happened-to-execute-in-plac...
This is a good article! I guess you're right that when you're running code loaded over a QSPI bus it's probably going to be cached unless you're using an old chip. So data processed by code loaded that way is subject to timing-channel leaks.
However, I think it's very unusual for embedded NOR memory in a μC to have detectable variable access latency. As the article says:
> As long as the operating frequency is slow enough that the flash access times can keep up, instructions can be fetched and executed directly out of the flash, otherwise known as executed in place. The original idea was that you didn’t need to buffer the instructions somewhere else before executing them. ¶ Embedded NOR memory is still alive and well, although today’s higher volumes are on nodes far from what would be considered leading-edge for logic.
So, on-chip Flash is probably still fine.
You probably don't want to try to make an AVR8 into an SSL accelerator, but there are plenty of applications where the ability to do crypto securely is valuable, even if it's very slow.
Bitbanging protocols with tight timing requirements using cycle-accurate code is still a thing people routinely do on small microcontrollers, and it wouldn't work if instruction timing was as unpredictable as you're saying.
Nevertheless, I agree that removing data-dependent branches is a better way to close timing leaks.
If you bubble sort a list of bytes, say your algorithm runs in 10000+n^2 clock cycles. You have at most an exabyte of storage, so your code will run in at most 10^37 clock cycles! :p
As storage technology improves, of course the coefficient will increase, but at that point is should be considered a different algorithm. This one has undefined behaviour when you have more than an exabyte of storage.
In essence, this is about a programming language that can ensure that execution time always equals the worst case; if there's branching, taking both branches and ignoring one of the results; if there's iteration, doing a constant maximum count of iterations no matter what the input data is, etc.