Go 1.8.2 repairs P-256 subtraction on x86-64
A small assembly correction fixes a carry bug in the optimized P-256 implementation. The accompanying regression vectors explain the scope more precisely than a general security warning.
A cryptographic arithmetic routine can return the wrong result without producing a memory error or a crash. The P-256 correction in Go 1.8.2 is that kind of defect. A few assembly instructions choose between two candidate subtraction results, and the choice must reflect the correct arithmetic condition. Ordinary language-level memory safety does not establish that this choice is mathematically right.
The May 23 release entry identifies one security fix in crypto/elliptic. The versioned release diff narrows it to the x86-64 P-256 implementation and includes regression inputs for scalar multiplication. This is a small maintenance release with a specific arithmetic correction, not a change to the public elliptic-curve API.
I appreciate how much implementation work Go keeps below ordinary application code. Cryptography makes the dependence especially clear. A caller can choose a standard package and write legible code while still relying on an assembly routine whose correctness requires a different kind of review.
The reported failure
The original issue, opened on April 19, says Cloudflare reported a carry bug in the P-256 implementation it had contributed for x86-64. Adam Langley reports reproducing the discrepancy through randomized testing against BoringSSL. After applying the supplied patch, he could no longer reproduce it after approximately two to the thirty-first iterations.
That comparison is meaningful because it checks the result against another implementation. Running one implementation repeatedly and obtaining consistent answers would not show that its arithmetic agrees with the intended operation. Differential testing gives the random inputs an independent reference result and can expose a narrow arithmetic condition that normal examples rarely exercise.
The issue is also careful about security impact. It says the bug is not obviously exploitable while leaving open the possibility of an attack. That is the available assessment, and it does not support a claim that an attacker has demonstrated key recovery or a particular protocol compromise. A security release can be appropriate for incorrect cryptographic arithmetic even when the exploitability is unresolved.
This distinction prevents both overstatement and dismissal. The release repairs a real disagreement in an operation used by cryptographic code. The issue does not establish every possible consequence of that disagreement. Describing the correction precisely gives operators a reason to rebuild affected programs without inventing an incident or an exploit.
Where the condition goes wrong
The changed assembly lives in p256SubInternal. The Go 1.8.2 source shows a sequence of subtraction-with-borrow instructions followed by saved copies of the result words. A subsequent addition sequence forms another candidate. Conditional moves then select the result words to retain.
The diff changes the instruction immediately before those conditional moves. The older code uses ADCQ $0, mul0. Go 1.8.2 uses ANDQ $1, mul0, and changes the following conditional moves from CMOVQNE to CMOVQEQ. Both the condition-setting operation and the sense of the moves change together.
Reading only the number of altered lines would miss the significance. The conditional moves rely on processor flags left by a preceding instruction. Changing how those flags are set changes which arithmetic result the routine returns. The visible patch establishes that the selection condition needed correction, even though the public function signatures stay the same.
The subtraction routine operates on multiple machine words. That is why borrow and carry bookkeeping appears throughout the code. A condition that works for many inputs can still fail at a boundary reached by a particular combination of those words. The two added scalar-multiplication cases preserve concrete inputs for which the full operation must return known coordinates.
The patch credits Vlad Krasnov and records review through the Go change system. That attribution matters to the history of the repair because the issue identifies the original implementation and the submitted correction as coming from the same contributing organization. The release incorporates a reviewed patch and test cases into the maintenance branch rather than asking applications to avoid the standard API.
What the regression cases establish
The new test data contain a scalar, input coordinates, and expected output coordinates. The test parses the hexadecimal values into big integers, calls ScalarMult, and compares both returned coordinates with their expected values. A mismatch in either coordinate fails the test and prints the actual and expected point.
This checks an externally meaningful operation through the package API. It does not merely assert that a particular assembly instruction appears in the file. That makes the cases useful even if the implementation changes later, because the expected mathematical result remains the contract being tested.
The two techniques in the issue and the release complement each other. Random comparison against BoringSSL discovers discrepancies across many inputs. Fixed regression vectors preserve particular failures in the regular suite. The report that random testing no longer reproduced the problem is evidence supporting the patch, while the fixed cases make the discovered behavior repeatable.
Neither observation is a proof of every arithmetic path. The useful conclusion is narrower and concrete. The reported discrepancy has a correction, that correction changes the result-selection logic, and the release carries tests that check known scalar-multiplication results. Those are sufficient facts for explaining what this maintenance update actually contains.
Applying a compiler distribution fix
The release entry also records Go 1.7.6 on the same day with the same security correction. Users on the preceding release line therefore have a maintenance update without needing to adopt Go 1.8 first. The versioned documentation added with Go 1.8.2 confirms that both release entries were part of this update.
An installed compiler distribution and an already deployed executable are different artifacts. Updating the distribution changes the implementation available for subsequent builds. Programs that contain the affected implementation need a new build before their arithmetic can reflect the correction. The release does not change application source syntax or introduce a replacement curve API.
I regard this as a reason to track maintenance releases as part of operating Go software. The application-level code may remain unchanged while a dependency inside the standard distribution needs repair. Here the reason is identifiable down to a multiword subtraction routine, with a documented uncertainty about exploitability and concrete tests for the arithmetic result.