crypton-2.2.2: cbits/tests/ct/known.txt
# Places where a secret reaches a branch that are known, understood and not
# defects. A driver reporting only these passes; anything else fails.
#
# Every entry is "file:line what it is". Keep it short: a long one means
# something has been accepted that should have been fixed.
# assert() on a value derived from the secret. The asserted condition holds
# on every input -- these check an internal invariant of the reduction, not
# anything about the data -- so the branch goes the same way every time and
# no timing follows from it. They are reported because crypton's C is built
# without NDEBUG, so assert() is live in a released library. See the round
# eight notes in cbits/tests/ct/README.
p256.c:200 assert(top <= 1) in crypton_p256_modmul
p256.c:204 assert(top == 0) in crypton_p256_modmul
f_generic.c:94 assert on the borrow in crypton_gf_448_strong_reduce
f_generic.c:106 assert on the carry in crypton_gf_448_strong_reduce
# The same thing for a different reason. crypton_gf_invert asserts that what
# it inverted had an inverse, and the two callers that ask for the assertion
# are inverting a projective z, which is never zero for a point on the curve.
# So this one holds because of what the callers pass rather than because of
# arithmetic, and it too goes the same way on every valid input.
decaf.c:136 assert(ret) in crypton_gf_invert
# AArch64 only. gcc keeps a carry in the flags and takes it out with `cset`
# or `cinc`, where on x86-64 it uses `adc` and the carry never leaves the
# data path. memcheck calls `cset` a conditional move and reports it, and
# it attributes the report to the branch that ends the block rather than to
# the `cset` itself -- so the site it names is a loop back-edge, not the
# instruction that touched the secret.
#
# Checked by disassembling the address memcheck named, in a -no-pie build so
# that its addresses and objdump's agree. At every one of these the branch
# reads flags from a `cmp` against a loop counter or a pointer bound, both
# public; the only instructions consuming the secret's flags are `cset` and
# `cinc`, which do not branch and take the same time either way. In decaf's
# lookup the secret only reaches a `dup` and a NEON `and`/`orr`.
#
# 400f60 cmp x3, #0x20 <- public: four digits of 8 bytes
# 400f64 b.ne 400f3c <- what memcheck names
# 404c6c cmp x3, x6 <- public: j against n_table
# 404c70 b.ne 404c30 <- what memcheck names
addM@p256.c the carry of addM's loop, which is taken without a
# branch. Named by function rather than by line because
# the line is the compiler's choice and the function is
# not. Three compilers were asked: AArch64 names 147 and
# 149, gcc 11.5 on x86-64 names 147, 148 and 149, and the
# gcc 14 the CI uses names none of them -- and all three
# name addM.
#
# On AArch64 the only instructions consuming the secret's
# flags are cset and cinc, which do not branch. On x86-64,
# disassembled in a -no-pie build, the body between the
# loop label and its closing branch is
#
# 401ad6 mov (%rax,%rdx,1),%rbx
# 401aeb and %rcx,%rbx <- the secret, as a mask
# 401af1 add %r12,%r8
# 401af4 adc %r13,%r9 <- carried, not branched on
# 401afd mov %rsi,0x120(%rsp,%rdx,1)
# 401b0e cmp $0x20,%rdx <- public: the loop offset
# 401b12 jne 401ad6 <- the only branch
#
# one branch, on a public counter; no conditional move, and
# no address the secret reaches.
constant_time.h:150 decaf's constant-time lookup, over j < n_table