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