Source code for tlslite.utils.x25519

# Authors:
#   Hubert Kario (2017)
#
# See the LICENSE file for legal information regarding use of this file.

"""Handling X25519 and X448 curve based key agreement protocol."""

from .cryptomath import bytesToNumber, numberToByteArray, divceil
# the names of the variables come directly from RFC 7748 so changing them
# would make the code harder to audit/compare
# pylint: disable=invalid-name


[docs] def decodeUCoordinate(u, bits): """Function to decode the public U coordinate of X25519-family curves.""" if bits not in (255, 448): raise ValueError("Invalid number of expected bits") if bits % 8: u[-1] &= (1 << (bits % 8)) - 1 return bytesToNumber(u, endian="little")
[docs] def decodeScalar22519(k): """Function to decode the private K parameter of the x25519 function.""" k[0] &= 248 k[31] &= 127 k[31] |= 64 return bytesToNumber(k, endian="little")
[docs] def decodeScalar448(k): """Function to decode the private K parameter of the X448 function.""" k[0] &= 252 k[55] |= 128 return bytesToNumber(k, endian="little")
[docs] def cswap(swap, x_2, x_3): """Conditional swap function.""" if swap: return x_3, x_2 else: return x_2, x_3
X25519_G = numberToByteArray(9, 32, endian="little") X25519_ORDER_SIZE = 32
[docs] def x25519(k, u): """ Perform point multiplication on X25519 curve. :type k: bytearray :param k: random secret value (multiplier), should be 32 byte long :type u: bytearray :param u: curve generator or the other party key share :rtype: bytearray """ bits = 255 k = decodeScalar22519(k) u = decodeUCoordinate(u, bits) a24 = 121665 p = 2**255 - 19 return _x25519_generic(k, u, bits, a24, p)
X448_G = numberToByteArray(5, 56, endian="little") X448_ORDER_SIZE = 56
[docs] def x448(k, u): """ Perform point multiplication on X448 curve. :type k: bytearray :param k: random secret value (multiplier), should be 56 bytes long :type u: bytearray :param u: curve generator or the other party key share :rtype: bytearray """ bits = 448 k = decodeScalar448(k) u = decodeUCoordinate(u, bits) a24 = 39081 p = 2**448 - 2**224 - 1 return _x25519_generic(k, u, bits, a24, p)
def _x25519_generic(k, u, bits, a24, p): """Generic Montgomery ladder implementation of the x25519 algorithm.""" x_1 = u x_2 = 1 z_2 = 0 x_3 = u z_3 = 1 swap = 0 for t in range(bits-1, -1, -1): k_t = (k >> t) & 1 swap ^= k_t x_2, x_3 = cswap(swap, x_2, x_3) z_2, z_3 = cswap(swap, z_2, z_3) swap = k_t A = (x_2 + z_2) % p AA = pow(A, 2, p) B = (x_2 - z_2) % p BB = pow(B, 2, p) E = (AA - BB) % p C = (x_3 + z_3) % p D = (x_3 - z_3) % p DA = (D * A) % p CB = (C * B) % p x_3 = pow(DA + CB, 2, p) z_3 = (x_1 * pow(DA - CB, 2, p)) % p x_2 = (AA * BB) % p z_2 = (E * (AA + a24 * E)) % p x_2, x_3 = cswap(swap, x_2, x_3) z_2, z_3 = cswap(swap, z_2, z_3) ret = (x_2 * pow(z_2, p - 2, p)) % p return numberToByteArray(ret, divceil(bits, 8), endian="little") # pylint: enable=invalid-name