symm/gcm.c, symm/gcm-*.S, utils/gcm-ref: Replace one-bit shift with algebra.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 16 Jan 2024 14:03:11 +0000 (14:03 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 16 Jan 2024 14:03:11 +0000 (14:03 +0000)
commitac4a43c1da1d1554247212289cf483934b9e6d1c
tree51262b8ec9751e1c352c0f79bfc25ed66963f4f0
parent9f4db5004ef6239c8f50bae16df0e9df3bed4417
symm/gcm.c, symm/gcm-*.S, utils/gcm-ref: Replace one-bit shift with algebra.

The ARM32 and x86 instruction sets lack an instruction to reverse the
order of bits in each byte of a vector register.  Therefore, they
resolve the GCM bit-ordering nightmare by reordering the bytes and
working with reversed polynomials.  But when you multiply reversed
polynomials, the result ends up being shifted by one bit relative to the
answer you actually wanted -- and SIMD instruction sets are bad at
multiprecision bit shifts, so this involves a lot of work.

Instead, use algebra.  If the result is shifted by one bit position,
then it's been multiplied by the generator t.  We can therefore fix this
by dividing through by t.  Of course, this might not even be possible
working in general the ring of polynomials over GF(2), but we're
actually working in the GCM quotient field, and t definitely has an
inverse there.  Also, dividing by t will take time and effort -- but in
fact one of the operands is something we know ahead of time and get to
prepare in whatever way we like.  So, in particular, we could divide it
by t before we even start.

The result is that we get to delete a bunch of rather fiddly assembler
code, in favour of some fairly simple C setup (and extra compensation
work in `recover_k').

I stole this trick from PuTTY.
symm/gcm-arm-crypto.S
symm/gcm-x86ish-pclmul.S
symm/gcm.c
utils/gcm-ref