Elliptic Curve Operations ============================ In addition to high level operations for signatures, key agreement, and message encryption using elliptic curve cryptography, the library contains lower level interfaces for performing operations such as elliptic curve point multiplication. All operations described here are constant time (avoiding timing/cache based side channels) unless otherwise documented. Usually this is denoted by including `vartime` in the name. .. note:: Prior to 3.6.0, Botan used :cpp:class:`BigInt` to represent scalar values, and ``EC_Point`` for elliptic curve points in Jacobian projective form. ``EC_Point`` still exists, but is intentionally undocumented, and will be removed in Botan4. .. warning:: The following interfaces are used to implement the elliptic curve signature and key agreement schemes within the library. They are exposed to applications to allow creating custom protocols, such as for example a threshold signature scheme or a PAKE. Ordinary users do not need to use these, outside of perhaps something like deserializing a EC_Scalar and passing it to a constructor. .. cpp:class:: EC_Scalar An elliptic curve scalar; that is, an integer in the range ``[0,n)`` where ``n`` is size of the prime order subgroup generated by the standard group generator. Note that while zero is a representable value, some of the deserialization functions reject zero. .. cpp:function:: static std::optional deserialize(const EC_Group& group, std::span buf) Deserialize a scalar. The bytestring must be exactly the length of the group order; neither inputs with excess leading zero bytes nor short encodings are accepted. Returns ``nullopt`` if the length is incorrect or if the integer is not within the range ``[1,n)`` where ``n`` is the group order. .. cpp:function:: static EC_Scalar from_bytes_with_trunc(const EC_Group& group, std::span buf) Convert a bytestring to a scalar using the ECDSA truncation rules. This can return zero. .. cpp:function:: static EC_Scalar from_bytes_mod_order(const EC_Group& group, std::span buf) Treating the input as the big-endian encoding of an integer, reduce that integer modulo ``n``. The encoded integer should be no greater than ``n**2``. .. cpp:function:: static EC_Scalar random(const EC_Group& group, RandomNumberGenerator& rng) Return a random non-zero scalar value .. cpp:function:: static EC_Scalar gk_x_mod_order(const EC_Scalar& k, RandomNumberGenerator& rng) Compute the elliptic curve scalar multiplication (``g*k``) where ``g`` is the standard base point on the curve. Then extract the ``x`` coordinate of the resulting point, and reduce it modulo the group order. If ``k`` is zero (resulting in the scalar multiplication producing the identity element) then this function returns zero. .. cpp:function:: size_t bytes() const Return the byte length of the scalar .. cpp:function:: void serialize_to(std::span buf) const Serialize the scalar to the provided span. It must have length exactly equal to the value returned by :cpp:func:`bytes`. .. cpp:function:: bool is_zero() const Returns true if this scalar value is zero .. cpp:function:: bool is_nonzero() const Returns true if this scalar value is not zero .. cpp:function:: EC_Scalar invert() const Return the multiplicative inverse, or zero if `*this` is zero .. cpp:function:: EC_Scalar invert_vartime() const Same as :cpp:func:`EC_Scalar::invert`, except that the inversion is allowed to leak the value of the scalar to side channels. .. cpp:function:: EC_Scalar negate() const Return the additive inverse .. cpp:function:: EC_Scalar operator+(const EC_Scalar& x, const EC_Scalar& y) Addition modulo `n` .. cpp:function:: EC_Scalar operator-(const EC_Scalar& x, const EC_Scalar& y) Subtraction modulo `n` .. cpp:function:: EC_Scalar operator*(const EC_Scalar& x, const EC_Scalar& y) Multiplication modulo `n` .. cpp:function:: bool operator==(const EC_Scalar& x, const EC_Scalar& y) Equality test .. cpp:class:: EC_AffinePoint A point on the elliptic curve. .. cpp:function:: static EC_AffinePoint::generator(const EC_Group& group) Return the standard generator of the group .. cpp:function:: static EC_AffinePoint::identity(const EC_Group& group) Return the identity element of the group (aka the point at infinity) .. cpp:function:: EC_AffinePoint(const EC_Group& group, std::span bytes) Point deserialization. Throws if invalid, including if the point is not on the curve. This accepts SEC1 compressed or uncompressed formats .. cpp:function:: static std::optional deserialize(const EC_Group& group, std::span bytes) Point deserialization. Returns ``nullopt`` if invalid, including if the point is not on the curve. This accepts SEC1 compressed or uncompressed formats .. cpp:function:: bool is_identity() const Return true if this point is the identity element. .. cpp:function:: EC_AffinePoint mul(const EC_Scalar& scalar, RandomNumberGenerator& rng) const Variable base scalar multiplication. Constant time. If the rng object is seeded, also uses blinding and point rerandomization. .. cpp:function:: static EC_AffinePoint g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng) Fixed base scalar multiplication. Constant time. If the rng object is seeded, also uses blinding and point rerandomization. .. cpp:function:: static std::optional mul_px_qy(const EC_AffinePoint& p, \ const EC_Scalar& x, \ const EC_AffinePoint& q, \ const EC_Scalar& y, \ RandomNumberGenerator& rng) Constant time 2-ary multiscalar multiplication. Returns p*x + q*y, or nullopt if the resulting point was the identity element. .. cpp:function:: static EC_AffinePoint add(const EC_AffinePoint& p, const EC_AffinePoint& q) Elliptic curve point addition. .. note:: This point addition operation is relatively quite expensive since it must convert the point directly from projective to affine coordinates, which requires an expensive field inversion. This is, however, sufficient for protocols which just require a small number of point additions. In the future a public type for projective coordinate points may also be added, to better handle protocols which require many point additions. If you are implementing such a protocol using this interface please open an issue on Github. .. cpp:function:: EC_AffinePoint negate() const Return the negation of this point. .. cpp:function:: static EC_AffinePoint hash_to_curve_ro(const EC_Group& group, \ std::string_view hash_fn, \ std::span input, \ std::span domain_sep) Hash to curve (RFC 9380), random oracle variant. This is currently only supported for a few curves. .. cpp:function:: static EC_AffinePoint hash_to_curve_nu(const EC_Group& group, \ std::string_view hash_fn, \ std::span input, \ std::span domain_sep) Hash to curve (RFC 9380), non-uniform variant. This is currently only supported for a few curves. .. cpp:function:: size_t field_element_bytes() const Return the size of the ``x`` and ``y`` coordinates, in bytes. .. cpp:function:: void serialize_x_to(std::span bytes) const Serialize the ``x`` coordinate to the output span, which must be exactly of the expected size (1 field element) .. cpp:function:: void serialize_y_to(std::span bytes) const Serialize the ``y`` coordinate to the output span, which must be exactly of the expected size (1 field element) .. cpp:function:: void serialize_xy_to(std::span bytes) const Serialize the ``x`` and ``y`` coordinates to the output span, which must be exactly of the expected size (2 field elements) .. cpp:function:: void serialize_compressed_to(std::span bytes) const Serialize the compressed SEC1 encoding to the output span, which must be exactly of the expected size (1 field element plus 1 byte) .. cpp:function:: void serialize_uncompressed_to(std::span bytes) const Serialize the uncompressed SEC1 encoding to the output span, which must be exactly of the expected size (2 field elements plus 1 byte) .. cpp:class:: EC_Group::Mul2Table This class stores precomputed tables for variable time 2-ary multiplications. These are commonly used when verifying elliptic curve signatures. .. cpp:function:: Mul2Table(const EC_AffinePoint& h) Set up a table for computing ``g*x + h*y`` where ``g`` is the group generator. .. cpp:function:: std::optional mul2_vartime(const EC_Scalar& x, const EC_Scalar& y) const Return ``g*x + h*y``, where it allowed to leak the values of ``x`` and ``y`` to side channels. This returns ``nullopt`` if the product was the point at infinity. .. cpp:function:: bool mul2_vartime_x_mod_order_eq(const EC_Scalar& v, const EC_Scalar& x, const EC_Scalar& y) const Compute ``g*x + h*y``, then extract the ``x`` coordinate of that point. Reduce the ``x`` coordinate modulo the group order, then check if that value equals ``v``. This is faster that using :cpp:func:`EC_Group::Mul2Table::mul2_vartime` for this process, because this function can avoid converting the point out of projective coordinates.