
A Go implementation of Poly1305 that makes sense - pentestercrab
https://blog.filippo.io/a-literate-go-implementation-of-poly1305/
======
zimmerfrei
One reason this cannot be translated into a portable C version while retaining
its compactness (and readability) is the lack of support for carry/borrow
chains.

In Go, bits.Add64 takes as input and returns the carry.

In C, there are some constructs that modern compilers will recognize as
patterns people use to extract the carry, but it is a hit-and-miss.

Even compiler-specific intrinsics are a few and far between, inefficient or
even broken.

~~~
boomlinde
If you look into the implementations of Add64/Sub64/Mul64 you'll see that it's
not a lot of code and that there is nothing magical about them. They can just
as easily be implemented in C in some 30 lines of code. Because they concern
unsigned integers only there is no UB to consider on overflow/carry.

~~~
giovannibajo1
Actually, those functions are intrinsics in the Go compiler on many platforms,
so the compiler generates a single ADD / ADC opcode. The source code that you
see is a fallback for backends that have not implemented them as intrinsics
yet.

~~~
leni536
gcc can optimize generic code for a carry check. To be fair both clang and
msvc fails to optimize this specific case.

[https://godbolt.org/z/6WXfnL](https://godbolt.org/z/6WXfnL)

Edit: OK, I have much worse time generating "adc" instructions, and only gcc
sees the opportunity to emit "setc" where appropriate. I see the issue now.

~~~
giovannibajo1
Correct, gcc can generate "setc" but not "adc", AFAIK.

------
tarikjn
Great write-up, I haven't dug into understanding the whole code yet, but
perhaps someone can answer this for me: can the code be made even simpler
using Go's bignum: big.Int?

~~~
CaliforniaKarl
One concern may be the lack of a constant-time guarantee. If there are any
optimizations that run differently depending on the numbers involved, then
that may be an opening to a side-channel attack.

~~~
Someone
Upvoted, but such optimizations might exist for integer math, too. I’m not
aware of any compiler that gives constant-time guarantees.

The best you can do is to write statements that you think map to certain
instructions, and to check every release build to see what instructions the
compiler chose.

You also may have to make sure that the buffers you use don’t cross page
boundaries.

~~~
londons_explore
Unit tests that throw random numbers into the code and check execution time is
always a constant number of clock cycles should catch nearly all timing side
channels.

~~~
dfranke
That won't work. When we say "constant-time code" what we really mean is "code
whose running time is independent of its input". It won't really be constant
due to factors like the OS scheduler and the initial state of the CPU's
instruction cache.

What you really want is
[https://github.com/agl/ctgrind](https://github.com/agl/ctgrind) or something
similar.

------
simonhorlick
I find a lot of go libraries are very well commented and very accessible, but
the standard library and especially the crypto stuff is very sparsely
commented.

