simon-git: putty (main): Simon Tatham
Commits to Tartarus hosted VCS
tartarus-commits at lists.tartarus.org
Wed Jan 14 12:51:54 GMT 2026
TL;DR:
c15d4d7b Fix edge case in ecc_weierstrass_add_general doubling.
Repository: https://git.tartarus.org/simon/putty.git
On the web: https://git.tartarus.org/?p=simon/putty.git
Branch updated: main
Committer: Simon Tatham <anakin at pobox.com>
Date: 2026-01-14 12:51:54
commit c15d4d7b1acf99ae21c67f5c7c65884b9959149d
web diff https://git.tartarus.org/?p=simon/putty.git;a=commitdiff;h=c15d4d7b1acf99ae21c67f5c7c65884b9959149d;hp=fd08a7754bbc94ec7fb841c4858897d8ea9f448c
Author: Simon Tatham <anakin at pobox.com>
Date: Wed Jan 14 12:47:23 2026 +0000
Fix edge case in ecc_weierstrass_add_general doubling.
ecc_weierstrass_add_general() is the function that you call to compute
P+Q if you don't know whether or not P=Q (in which case different
calculations are required). It calculates the answers for both the Pâ Q
and P=Q cases, and selects between them (in constant time, so as not
to give away whether P=Q).
But we use Jacobian coordinates (two numerators and a denominator) to
represent Weierstrass curve points, so a point has multiple
representations, using different choices of denominator. In the case
where P and Q were different representations of the same point, using
different denominators, ecc_weierstrass_add_general() was doing the
wrong thing, and returning something that wasn't even a valid elliptic
curve point.
The root cause was that we start by transforming both inputs to be
over a common denominator for the Pâ Q case, and we should have done
the P=Q calculations relative to _that_ denominator, which is the one
expected by the shared epilogue code. But instead we used the
denominator of one of the input points. And if P,Q have identical
_representations_, then this makes no difference, so the existing
tests of adding a point to itself didn't spot the problem.
This is a bug in our ECC arithmetic, but happily, not a vulnerability,
because exploiting it requires work equivalent to recovering the
private key.
ecc_weierstrass_add_general() is used when validating an ECDSA
signature: you use it to calculate (hw)G + (rw)P, where G is the group
generator, P is the public key, h is derived from a hash of the
message, and r,w come from the signature. So to trigger the bug you
need the two addends to be the same, i.e. (hw)G = (rw)P. Cancelling w,
you need hG = rP.
But if an attacker trying to forge a signature was able to find any
pair (h,r) at all such that hG = rP, then inverting r mod the group
order and multiplying both sides by its inverse râ»Â¹, you would have
(râ»Â¹h)G = (râ»Â¹r)P = P. And that would mean râ»Â¹h was precisely the
private key.
So if an attacker could do that at all, then they wouldn't _need_ to
exploit any buggy behaviour in ecc_weierstrass_add_general(). They'd
have the private key by that point, so they could use it to construct
a signature that _didn't_ trigger this bug, and that PuTTY would
accept with or without the bug fix.
Thanks to Guido Vranken for the report.
crypto/ecc-arithmetic.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
crypto/ecc.h | 6 ++++++
test/cryptsuite.py | 7 +++++++
test/testcrypt-func.h | 2 ++
4 files changed, 61 insertions(+), 2 deletions(-)
More information about the tartarus-commits
mailing list