A Cryptographic Near Miss
words.filippo.io
words.filippo.io
Today's Go compiler. This feels like a belief with a lot of potential for generating near misses of its own.
Anyway, we're not moving all cryptography to assembly anytime soon, and I'm positive that would not be a net increase in security, even if it would mitigate the hypothetical risk of compiler-introduced side-channels.
> The second, more interesting lesson is that while assumptions might be valid now, they aren’t guaranteed to be valid in the future, after the code is refactored or reused over the years. It’s important to minimize assumptions and clearly document the remaining ones, as much as possible into the API or type system, and otherwise in high-level comments.
A lot of software engineering lessons can be reduced to “minimize assumptions and dependencies”. This includes the assumption that assumptions won’t change in the future.
Doesn't do anything for this bug, which was an ASM issue. There's nothing you can do about this sort of bug except give people a better idea of the risks (e.g., make it clear that they can trade safety for performance.)
Here we had: 1) incomplete addition that had to be called with different points; and consequently 2) scalar multiplication that had to be called with a reduced scalar so the computation wouldn't wrap and add two equal points. I don't think we have the tools to encode (1), nor the fact that (2) satisfies (1). (2) maybe could have been encoded in the type system by accepting a ReducedScalar.
Formal verification with typechecking sucks and is very limited.
data P1 a
data P2 a
data PointNotEqual where
| T :: P1 a -> P2 a -> PointNotEqual
getP1 :: P1 a -> Point
getP2 :: P2 a -> Point
checkNE :: Point -> Point -> Maybe PointNotEqual
(+) :: P1 a -> P2 a -> Point
Here when you are given a PointNotEqual, you don’t know what the type variable is, only that it’s the same between the two points. So you (ie the compiler) cannot prove that a P1 or P2 from a different call to PointNotEqual has the same type variable, so you can’t add them.But these types also mean you need to do the check before every addition which defeats the point of the whole constant time thing, so the typechecking is still limited. And I guess you can’t do it in Go either.
Nitpick: the important point here is that points on the elliptic curve have order (by definition the smallest k such that kP = identity), and the group of such points has order (by definition, the number of elements it has). Here, scalar is just a way to say "not a point", or "integer value" and if you define them in the right group, sure, we could talk about their order as well, but what we actually care about is the order of the points.
From the definition of order, qP = identity, thus (q+30)P = qP + 30P = identity + 30P = 30P, hence the wrapping.
> Fundamentally, a scalar multiplication function was returning the wrong value for a very specific input because of a combination of the pre-existing complexity and unsafety of some optimized assembly, of undocumented assumptions, and of the neverending state of flux of open source code.
So, basically, it's everybody's fault except for the maintainer of the go crypto code. Which, coincidentally, is the guy writing this blog post.
Oh, pre-existing complexity, huh? I wonder who put that there. It probably fell from the heavens.
I would certainly feel much safer using code from someone who is able to say they made a mistake. This is not about blame. This is about being able to take responsibility.
I wouldn't have said anything if the whole tone of this blog post wasn't "here, children, let me tell you something you can learn from". How about you learn from it first, Obi Wan?
Now feel free to downvote me, you hypocrites.
From some discussions I had with filippo years ago it sounded like he agreed and was trying to clean parts of these now that he was working there. It looks like progress is being made, and if he can share his learnings along the way let’s benefit from that instead of being mad at him no? Sharing is caring.
I mean even in a world where he would have written that code originally, what’s wrong with being transparent about it? Everybody writes bugs.
As a fan of filippo and and avid hater of evil-Google, I am pleased to point out that....
"Last May I left my job on the Go team at Google"[1]
I have no beef with either Filippo or Google or Go. Or you for that matter. But this weaseling needs to stop.
Now feel free to downvote me, you hypocrites.
Huh ? When did I say that ?
I posted what I did because the OP made it sound like filippo was still working at Google.
I just wanted to point out that as of next month it will have been a year since filippo left.
Beyond that, I was NOT proferring any sort of opinion on what fillipo may or may not have done whilst wearing the Google hat.
After he was responsible for that code for years, he now goes public and matter of factly states that all the code was shit the whole time.
Well why didn't he do anything about it then? What did he think the job description of being maintainer entailed?
Filippo wasted no time shitting on other crypto projects, like GnuPG, from what then looked like the high ground. And now he leaves Google and by the way the supposed high ground was an optical illusion (and that's the charitable phrasing).
My theory is that you people like this kind of story because it helps you cope with your own mediocrity. If Google and Golang have this kind of laissez-faire approach, why should I have higher standards? We'll just call it a life lesson as if it was handed down from heaven, as if things HAD to be this bad.
Sprinkle some "bugs happen to anyone" and "you can't have 100% security anyway" on top and your shit burger is finished.
Now feel free to downvote me, you hypocrites!
I mean, yeah. both of these statements are unconditionally true.