Complete rewrite of PuTTY's bignum library.
The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
2018-12-31 16:53:41 +03:00
|
|
|
#ifndef PUTTY_ECC_H
|
|
|
|
#define PUTTY_ECC_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Arithmetic functions for the various kinds of elliptic curves used
|
|
|
|
* by PuTTY's public-key cryptography.
|
|
|
|
*
|
|
|
|
* All of these elliptic curves are over the finite field whose order
|
|
|
|
* is a large prime p. (Elliptic curves over a field of order 2^n are
|
|
|
|
* also known, but PuTTY currently has no need of them.)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Weierstrass curves (or rather, 'short form' Weierstrass curves).
|
|
|
|
*
|
|
|
|
* A curve in this form is defined by two parameters a,b, and the
|
|
|
|
* non-identity points on the curve are represented by (x,y) (the
|
|
|
|
* 'affine coordinates') such that y^2 = x^3 + ax + b.
|
|
|
|
*
|
|
|
|
* The identity element of the curve's group is an additional 'point
|
|
|
|
* at infinity', which is considered to be the third point on the
|
|
|
|
* intersection of the curve with any vertical line. Hence, the
|
|
|
|
* inverse of the point (x,y) is (x,-y).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create and destroy Weierstrass curve data structures. The mandatory
|
|
|
|
* parameters to the constructor are the prime modulus p, and the
|
|
|
|
* curve parameters a,b.
|
|
|
|
*
|
|
|
|
* 'nonsquare_mod_p' is an optional extra parameter, only needed by
|
|
|
|
* ecc_edwards_point_new_from_y which has to take a modular square
|
|
|
|
* root. You can pass it as NULL if you don't need that function.
|
|
|
|
*/
|
|
|
|
WeierstrassCurve *ecc_weierstrass_curve(
|
|
|
|
mp_int *p, mp_int *a, mp_int *b, mp_int *nonsquare_mod_p);
|
|
|
|
void ecc_weierstrass_curve_free(WeierstrassCurve *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create points on a Weierstrass curve, given the curve.
|
|
|
|
*
|
|
|
|
* point_new_identity returns the special identity point.
|
|
|
|
* point_new(x,y) returns the non-identity point with the given affine
|
|
|
|
* coordinates.
|
|
|
|
*
|
|
|
|
* point_new_from_x constructs a non-identity point given only the
|
|
|
|
* x-coordinate, by using the curve equation to work out what y has to
|
|
|
|
* be. Of course the equation only tells you y^2, so it only
|
|
|
|
* determines y up to sign; the parameter desired_y_parity controls
|
|
|
|
* which of the two values of y you get, by saying whether you'd like
|
|
|
|
* its minimal non-negative residue mod p to be even or odd. (Of
|
|
|
|
* course, since p itself is odd, exactly one of y and p-y is odd.)
|
|
|
|
* This function has to take a modular square root, so it will only
|
|
|
|
* work if you passed in a non-square mod p when constructing the
|
|
|
|
* curve.
|
|
|
|
*/
|
|
|
|
WeierstrassPoint *ecc_weierstrass_point_new_identity(WeierstrassCurve *curve);
|
|
|
|
WeierstrassPoint *ecc_weierstrass_point_new(
|
|
|
|
WeierstrassCurve *curve, mp_int *x, mp_int *y);
|
|
|
|
WeierstrassPoint *ecc_weierstrass_point_new_from_x(
|
|
|
|
WeierstrassCurve *curve, mp_int *x, unsigned desired_y_parity);
|
|
|
|
|
|
|
|
/* Memory management: copy and free points. */
|
|
|
|
WeierstrassPoint *ecc_weierstrass_point_copy(WeierstrassPoint *wc);
|
|
|
|
void ecc_weierstrass_point_free(WeierstrassPoint *point);
|
|
|
|
|
|
|
|
/* Check whether a point is actually on the curve. */
|
|
|
|
unsigned ecc_weierstrass_point_valid(WeierstrassPoint *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add two points and return their sum. This function is fully
|
|
|
|
* general: it should do the right thing if the two inputs are the
|
|
|
|
* same, or if either (or both) of the input points is the identity,
|
|
|
|
* or if the two input points are inverses so the output is the
|
|
|
|
* identity. However, it pays for that generality by being slower than
|
|
|
|
* the special-purpose functions below..
|
|
|
|
*/
|
|
|
|
WeierstrassPoint *ecc_weierstrass_add_general(
|
|
|
|
WeierstrassPoint *, WeierstrassPoint *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fast but less general arithmetic functions: add two points on the
|
|
|
|
* condition that they are not equal and neither is the identity, and
|
|
|
|
* add a point to itself.
|
|
|
|
*/
|
|
|
|
WeierstrassPoint *ecc_weierstrass_add(WeierstrassPoint *, WeierstrassPoint *);
|
|
|
|
WeierstrassPoint *ecc_weierstrass_double(WeierstrassPoint *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute an integer multiple of a point. Not guaranteed to work
|
|
|
|
* unless the integer argument is less than the order of the point in
|
|
|
|
* the group (because it won't cope if an identity element shows up in
|
|
|
|
* any intermediate product).
|
|
|
|
*/
|
|
|
|
WeierstrassPoint *ecc_weierstrass_multiply(WeierstrassPoint *, mp_int *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query functions to get the value of a point back out. is_identity
|
|
|
|
* tells you whether the point is the identity; if it isn't, then
|
|
|
|
* get_affine will retrieve one or both of its affine coordinates.
|
|
|
|
* (You can pass NULL as either output pointer, if you don't need that
|
|
|
|
* coordinate as output.)
|
|
|
|
*/
|
|
|
|
unsigned ecc_weierstrass_is_identity(WeierstrassPoint *wp);
|
|
|
|
void ecc_weierstrass_get_affine(WeierstrassPoint *wp, mp_int **x, mp_int **y);
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Montgomery curves.
|
|
|
|
*
|
|
|
|
* A curve in this form is defined by two parameters a,b, and the
|
2019-01-03 18:26:33 +03:00
|
|
|
* curve equation is by^2 = x^3 + ax^2 + x.
|
Complete rewrite of PuTTY's bignum library.
The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
2018-12-31 16:53:41 +03:00
|
|
|
*
|
|
|
|
* As with Weierstrass curves, there's an additional point at infinity
|
|
|
|
* that is the identity element, and the inverse of (x,y) is (x,-y).
|
|
|
|
*
|
|
|
|
* However, we don't actually work with full (x,y) pairs. We just
|
|
|
|
* store the x-coordinate (so what we're really representing is not a
|
|
|
|
* specific point on the curve but a two-point set {P,-P}). This means
|
|
|
|
* you can't quite do point addition, because if you're given {P,-P}
|
|
|
|
* and {Q,-Q} as input, you can work out a pair of x-coordinates that
|
|
|
|
* are those of P-Q and P+Q, but you don't know which is which.
|
|
|
|
*
|
|
|
|
* Instead, the basic operation is 'differential addition', in which
|
|
|
|
* you are given three parameters P, Q and P-Q and you return P+Q. (As
|
|
|
|
* well as disambiguating which of the possible answers you want, that
|
|
|
|
* extra input also enables a fast formulae for computing it. This
|
|
|
|
* fast formula is more or less why Montgomery curves are useful in
|
|
|
|
* the first place.)
|
|
|
|
*
|
|
|
|
* Doubling a point is still possible to do unambiguously, so you can
|
|
|
|
* still compute an integer multiple of P if you start by making 2P
|
|
|
|
* and then doing a series of differential additions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create and destroy Montgomery curve data structures.
|
|
|
|
*/
|
|
|
|
MontgomeryCurve *ecc_montgomery_curve(mp_int *p, mp_int *a, mp_int *b);
|
|
|
|
void ecc_montgomery_curve_free(MontgomeryCurve *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create, copy and free points on the curve. We don't need to
|
|
|
|
* explicitly represent the identity for this application.
|
|
|
|
*/
|
|
|
|
MontgomeryPoint *ecc_montgomery_point_new(MontgomeryCurve *mc, mp_int *x);
|
|
|
|
MontgomeryPoint *ecc_montgomery_point_copy(MontgomeryPoint *orig);
|
|
|
|
void ecc_montgomery_point_free(MontgomeryPoint *mp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Basic arithmetic routines: differential addition and point-
|
|
|
|
* doubling. Each of these assumes that no special cases come up - no
|
|
|
|
* input or output point should be the identity, and in diff_add, P
|
|
|
|
* and Q shouldn't be the same.
|
|
|
|
*/
|
|
|
|
MontgomeryPoint *ecc_montgomery_diff_add(
|
|
|
|
MontgomeryPoint *P, MontgomeryPoint *Q, MontgomeryPoint *PminusQ);
|
|
|
|
MontgomeryPoint *ecc_montgomery_double(MontgomeryPoint *P);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute an integer multiple of a point.
|
|
|
|
*/
|
|
|
|
MontgomeryPoint *ecc_montgomery_multiply(MontgomeryPoint *, mp_int *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the affine x-coordinate of a point.
|
|
|
|
*/
|
|
|
|
void ecc_montgomery_get_affine(MontgomeryPoint *mp, mp_int **x);
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Twisted Edwards curves.
|
|
|
|
*
|
|
|
|
* A curve in this form is defined by two parameters d,a, and the
|
|
|
|
* curve equation is a x^2 + y^2 = 1 + d x^2 y^2.
|
|
|
|
*
|
|
|
|
* Apparently if you ask a proper algebraic geometer they'll tell you
|
|
|
|
* that this is technically not an actual elliptic curve. Certainly it
|
|
|
|
* doesn't work quite the same way as the other kinds: in this form,
|
|
|
|
* there is no need for a point at infinity, because the identity
|
|
|
|
* element is represented by the affine coordinates (0,1). And you
|
|
|
|
* invert a point by negating its x rather than y coordinate: the
|
|
|
|
* inverse of (x,y) is (-x,y).
|
|
|
|
*
|
|
|
|
* The usefulness of this representation is that the addition formula
|
|
|
|
* is 'strongly unified', meaning that the same formula works for any
|
|
|
|
* input and output points, without needing special cases for the
|
|
|
|
* identity or for doubling.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create and destroy Edwards curve data structures.
|
|
|
|
*
|
|
|
|
* Similarly to ecc_weierstrass_curve, you don't have to provide
|
|
|
|
* nonsquare_mod_p if you don't need ecc_edwards_point_new_from_y.
|
|
|
|
*/
|
|
|
|
EdwardsCurve *ecc_edwards_curve(
|
|
|
|
mp_int *p, mp_int *d, mp_int *a, mp_int *nonsquare_mod_p);
|
|
|
|
void ecc_edwards_curve_free(EdwardsCurve *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create points.
|
|
|
|
*
|
|
|
|
* There's no need to have a separate function to create the identity
|
|
|
|
* point, because you can just pass x=0 and y=1 to the usual function.
|
|
|
|
*
|
|
|
|
* Similarly to the Weierstrass curve, ecc_edwards_point_new_from_y
|
|
|
|
* creates a point given only its y-coordinate and the desired parity
|
|
|
|
* of its x-coordinate, and you can only call it if you provided the
|
|
|
|
* optional nonsquare_mod_p argument when creating the curve.
|
|
|
|
*/
|
|
|
|
EdwardsPoint *ecc_edwards_point_new(
|
|
|
|
EdwardsCurve *curve, mp_int *x, mp_int *y);
|
|
|
|
EdwardsPoint *ecc_edwards_point_new_from_y(
|
|
|
|
EdwardsCurve *curve, mp_int *y, unsigned desired_x_parity);
|
|
|
|
|
|
|
|
/* Copy and free points. */
|
|
|
|
EdwardsPoint *ecc_edwards_point_copy(EdwardsPoint *ec);
|
|
|
|
void ecc_edwards_point_free(EdwardsPoint *point);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Arithmetic: add two points, and calculate an integer multiple of a
|
|
|
|
* point.
|
|
|
|
*/
|
|
|
|
EdwardsPoint *ecc_edwards_add(EdwardsPoint *, EdwardsPoint *);
|
|
|
|
EdwardsPoint *ecc_edwards_multiply(EdwardsPoint *, mp_int *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query functions: compare two points for equality, and return the
|
|
|
|
* affine coordinates of a point.
|
|
|
|
*/
|
|
|
|
unsigned ecc_edwards_eq(EdwardsPoint *, EdwardsPoint *);
|
|
|
|
void ecc_edwards_get_affine(EdwardsPoint *wp, mp_int **x, mp_int **y);
|
|
|
|
|
|
|
|
#endif /* PUTTY_ECC_H */
|