Hacktakes · Edition 5
Hacktakes · Edition 5 · July 8, 2026

leaving crypto to the experts

Elite cryptography teams ship elementary bugs because corporate metrics reward feature velocity while economically punishing pedantic rigor.

By Wren Okada

Sparked by AI Meets Cryptography 1: What AI Found in Cloudflare's Circl · discussion

The top-level vulnerabilities are catastrophic, but the time-to-market was phenomenal.
The top-level vulnerabilities are catastrophic, but the time-to-market was phenomenal.

I was reading through a recent audit of CIRCL and noticed a snippet of code doing a float64 conversion inside a Shamir secret sharing implementation. As a rule, I assume I'm misreading something when I see an anomaly this baffling in a tier-1 repository, so I read through the raw source to see if this is actually what expert production code looks like.

Lately, I've suspected that our baseline assumptions about specialized infrastructure are completely decoupled from reality. The prevailing wisdom in software engineering—which you hear repeated as a thought-terminating cliché in basically every security discussion—is the advice to never roll your own crypto, which is generally sound advice given how easy it is to introduce obscure timing side-channels, leak key material through memory mismanagement, or accidentally skip a bounds check. We are told to delegate this entirely to the experts at infrastructure giants, pointing to libraries like Cloudflare's flagship cryptographic repository as the gold standard of safety because they are maintained by dedicated teams who theoretically spend their days thinking about prime fields, O(1) constant-time execution, and rigorous formal verification.

When this audit dropped, the public reaction followed a highly predictable script. If you look at the Hacker News discussion of the audit, the dominant sentiment is utter disbelief that experts could make such basic errors, encapsulated by comments expressing terror that using floats for cryptography is a mistake you would expect from a bootcamp graduate rather than a dedicated cryptography team.

This is the standard internet reaction to discovering catastrophic typos in critical infrastructure. The assumption is that someone, somewhere, simply forgot to hire smart people, but examining the code flagged by the auditors reveals a structural failure rather than a simple lapse in talent acquisition. The library evaluates a polynomial using math.Pow(float64(x), float64(i)) to calculate exact cryptographic integers.

If you aren't familiar with Go's type system or IEEE 754, it might be hard to grasp just how completely this breaks the fundamental mechanics of a finite field. Cryptography relies entirely on exact mathematics, where the loss of a single bit invalidates the mathematical proof backing the encryption. The Go standard library documentation for math.Pow strictly forces float64 coercion, meaning any arbitrary integer passed to it is instantly squeezed into a double-precision float regardless of the developer's intent.

When we check the specification for the 53-bit mantissa limit, a float64 can only represent integers exactly up to 2^53 - 1 (which is 9007199254740991). Cryptographic secrets are substantially larger than 53 bits. A standard elliptic curve like Curve25519 operates over a 255-bit prime field. The moment x exceeds the 53-bit threshold, mathematical precision is quietly destroyed by the floating-point unit because it simply does not have the physical bits required to store the exact integer. If you attempt to evaluate 2^53 + 1, the hardware mathematically rounds the value to 9007199254740992, meaning the lowest bit simply vanishes into the void. If you pass a 256-bit integer, you are discarding literally over two hundred bits of precision.

You are no longer doing exact arithmetic at this point. You are arbitrarily approximating the most significant bits of a shared secret, which breaks the cryptography so thoroughly that the resulting output is just random noise. The math is completely fabricated.

(Just as an aside, my strong suspicion for how this actually happens in practice is that researchers prototype these schemes in SageMath or Python, where operator overloading seamlessly handles arbitrarily large integers, and then a systems engineer hastily translates that prototype into Go without realizing that the underlying hardware abstractions are actively hostile to the math they are trying to do).

And this wasn't an isolated lapse in mathematical reasoning, because the exact same codebase contained a secondary bypass rooted in elementary syntax. In a parameter validation block designed to verify incoming cryptographic parameters, the authors attempted to match multiple valid cases using case a | b:.

According to the Go language specification on expression switch evaluation, a switch statement does not magically convert a bitwise OR into a logical OR instruction (even though that behavior might feel intuitive to developers coming from languages with advanced pattern matching). The compiler evaluates a | b as a single, static integer. If a is defined as 1 (binary 0001) and b is 2 (binary 0010), a | b evaluates to 3. The switch then checks if the provided parameter exactly equals that newly combined bitmask. This means passing a fails the check, passing b fails the check, and the validation only succeeds if an attacker passes an invalid, completely different identifier that happens to numerically match the bitwise OR of the two constants.

As I mentioned regarding the Hacker News thread, it's tempting to look at this and conclude that the specific engineers who wrote it are just incompetent. But if we actually look at the system, this library is maintained by a team of highly credentialed cryptographers at a company with massive resources. The actual failure mode here is that writing production software and researching cryptographic primitives require two completely disjoint sets of rigor, and the mechanisms we use to review code fundamentally fail to bridge that gap. We have this widely accepted cocktail party notion that hiring really smart people will automatically yield robust code, but intelligence doesn't override local incentive structures.

People want to believe that code quality is determined strictly by the mathematical pedigree of the authors. But a systemic anomaly like this persists because of how modern corporate engineering systems actually function at scale.

If we want to understand why teams of alleged experts keep shipping elementary syntax errors in cryptographic primitives, we can apply George Akerlof's market for lemons framework. In Akerlof's original economic paper, buyers of used cars cannot easily distinguish between a reliable car (a peach) and a defective one (a lemon), so they are only willing to pay a price that reflects the average quality of the entire market. Because the seller of a peach cannot get a premium for their high-quality car, they leave the market entirely, driving the average quality down until only lemons remain.

In a corporate engineering environment, the seller is the developer producing pull requests, and the buyer is the engineering management chain distributing promotions, bonuses, and performance ratings based on perceived output.

A severe information asymmetry exists between the developer shipping a feature and the management layer measuring their output. Management cannot easily distinguish between a deeply rigorous cryptography implementation and one that uses math.Pow(float64(x), float64(i)) but happens to pass the happy-path unit tests. This is especially true in an environment where QA has been historically hollowed out and engineers are expected to own their own testing infrastructure without actually being given the time budget to build it. To the velocity dashboard, a robust implementation and a structurally broken implementation look exactly the same: a closed Jira ticket and a merged feature branch.

We have built an entire hiring pipeline based on algorithmic hazing where candidates are expected to invert binary trees in twenty minutes or solve complex dynamic programming puzzles on a whiteboard. This heavily filters for people who can aggressively pattern-match Leetcode problems rather than people who possess the domain rigor to verify if a finite field boundary condition actually holds true in production memory. Once they are inside the company, this exact same behavioral loop is heavily reinforced by promo-driven development metrics.

Because thorough, adversarial code review produces no visible velocity metrics—while pushing new features yields immediate, measurable artifacts for performance reviews—the rational choice for an employee locally optimizing for their own career is to ship quickly and review casually. Any system that requires engineers to voluntarily sacrifice their own performance metrics to ensure global systemic safety is guaranteed to fail over a long enough timeline.

The developer who spends three days formally proving a 53-bit truncation bug exists in a peer's pull request gets zero credit on their velocity dashboard, while the developer who quickly rubber-stamps the feature keeps their pipeline moving and demonstrates high impact.

(I've skipped doing a deep dive into the reasons why peer review fails to reliably catch these issues since explaining that would balloon the word count of this post by at least an order of magnitude, but the short version is that humans are terrible at simultaneously reading for high-level algorithmic correctness and low-level memory layout constraints).

If you were to ask someone abstractly if their company wants to ship broken cryptography, they'd tell you no. But insofar as a company can be said to want anything, it wants what it incentivizes, and right now, the industry heavily incentivizes shipping fast while economically punishing the exact kind of pedantic rigor required to catch a 53-bit truncation.

← Back to Edition 5