The issue with writing crypto code in anything above assembly is that there's a risk that optimizing compilers could turn your finely crafted constant time, constant power code into something which is not that.
To my knowledge, the bigger reasons for writing assembly for low-level cryptography are (1) performance, and (2) avoiding UB. The latter, particularly around C's type promotion and signed integer shifting rules, are a significant source of bugs[1].
I think on some x86 cpu tuning levels this can happen around 1bit integers (aka bools) when the cost model says it's cheaper for whatever reason
(carry: bool, c: u64) = a.carrying_add(b)
d += carry as u64
could be turned into (carry: bool, c: u64) = a.carrying_add(b)
if carry
d += 1
And I recall doing some bittwiddling to get something like a cmov but the compiler recognized the pattern and turned it back into a branch (this was for performance optimization, not crypto, but still...)You can't count on that, especially if you give the compiler a loop that has a versioning opportunity.