Peter and I were discussing whether it is safe to use boolean negation to produce the control flag for cmov, e.g.
cmov(ss,kr,KYBER_SYMBYTES,!fail);
as he has done here. The risk is that the compiler may infer that !fail is 0/1 valued and then handle the two cases with a branch.
Crucially, this is only a problem if cmov can be inlined into decaps, and this can't happen given
the current factorization into verify.c and kem.c, and
the fact that we don't enable link-time optimization.
But I'm worried that downstream consumers of this code might concatenate the source files before compilation.
The value barrier used here is the same countermeasure that BoringSSL used when clang started to recognize (mask & x) | (~mask & y) as selecting between x and y. For what it's worth, compilers don't (yet) seem to recognize x ^ (mask & (x ^ y)), or the pattern in avx2/verify.c, as selecting between x and y.
Peter and I were discussing whether it is safe to use boolean negation to produce the control flag for
cmov
, e.g.as he has done here. The risk is that the compiler may infer that
!fail
is 0/1 valued and then handle the two cases with a branch.Crucially, this is only a problem if
cmov
can be inlined intodecaps
, and this can't happen givenverify.c
andkem.c
, andBut I'm worried that downstream consumers of this code might concatenate the source files before compilation.
The value barrier used here is the same countermeasure that BoringSSL used when clang started to recognize
(mask & x) | (~mask & y)
as selecting betweenx
andy
. For what it's worth, compilers don't (yet) seem to recognizex ^ (mask & (x ^ y))
, or the pattern inavx2/verify.c
, as selecting betweenx
andy
.