Skip to content

Commit

Permalink
Initial Curve448 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Legrandin committed Sep 5, 2024
1 parent ee9a360 commit 4a84913
Show file tree
Hide file tree
Showing 12 changed files with 817 additions and 24 deletions.
57 changes: 55 additions & 2 deletions lib/Crypto/PublicKey/_montgomery.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

from ._curve import _Curve
from Crypto.Math.Numbers import Integer
from Crypto.Util._raw_api import load_pycryptodome_raw_lib
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer,
SmartPointer)


def curve25519_curve():
Expand All @@ -15,7 +16,8 @@ def curve25519_curve():
int curve25519_new_point(Point **out,
const uint8_t x[32],
size_t modsize);
size_t modsize,
const void* context);
int curve25519_clone(Point **P, const Point *Q);
void curve25519_free_point(Point *p);
int curve25519_get_x(uint8_t *xb, size_t modsize, Point *p);
Expand Down Expand Up @@ -44,3 +46,54 @@ class EcLib(object):
None,
EcLib)
return curve25519


def curve448_curve():
p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1
order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3

_curve448_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._curve448", """
typedef void Curve448Context;
typedef void Curve448Point;
int curve448_new_context(Curve448Context **pec_ctx);
void curve448_free_context(Curve448Context *ec_ctx);
int curve448_new_point(Curve448Point **out,
const uint8_t *x,
size_t len,
const Curve448Context *ec_ctx);
void curve448_free_point(Curve448Point *p);
int curve448_clone(Curve448Point **P, const Curve448Point *Q);
int curve448_get_x(uint8_t *xb, size_t modsize, const Curve448Point *p);
int curve448_scalar(Curve448Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed);
int curve448_cmp(const Curve448Point *ecp1, const Curve448Point *ecp2);
""")

class EcLib(object):
new_context = _curve448_lib.curve448_new_context
free_context = _curve448_lib.curve448_free_context
new_point = _curve448_lib.curve448_new_point
clone = _curve448_lib.curve448_clone
free_point = _curve448_lib.curve448_free_point
get_x = _curve448_lib.curve448_get_x
scalar = _curve448_lib.curve448_scalar
cmp = _curve448_lib.curve448_cmp

curve448_context = VoidPointer()
result = EcLib.new_context(curve448_context.address_of())
if result:
raise ImportError("Error %d initializing Curve448 context" % result)

curve448 = _Curve(Integer(p),
None,
Integer(order),
Integer(9),
None,
None,
448,
"1.3.101.111", # RFC8410
SmartPointer(curve448_context.get(), EcLib.free_context),
"Curve448",
None,
EcLib)
return curve448
39 changes: 28 additions & 11 deletions lib/Crypto/PublicKey/_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CurveID(object):
ED25519 = 6
ED448 = 7
CURVE25519 = 8
CURVE448 = 9


class _Curves(object):
Expand All @@ -40,8 +41,10 @@ class _Curves(object):
ed25519_names = ["ed25519", "Ed25519"]
ed448_names = ["ed448", "Ed448"]
curve25519_names = ["curve25519", "Curve25519", "X25519"]
curve448_names = ["curve448", "Curve448", "X448"]

all_names = p192_names + p224_names + p256_names + p384_names + p521_names + ed25519_names + ed448_names + curve25519_names
all_names = p192_names + p224_names + p256_names + p384_names + p521_names + \
ed25519_names + ed448_names + curve25519_names + curve448_names

def __contains__(self, item):
return item in self.all_names
Expand Down Expand Up @@ -90,6 +93,11 @@ def load(self, name):
curve25519 = _montgomery.curve25519_curve()
curve25519.id = CurveID.CURVE25519
self.curves.update(dict.fromkeys(self.curve25519_names, curve25519))
elif name in self.curve448_names:
from . import _montgomery
curve448 = _montgomery.curve448_curve()
curve448.id = CurveID.CURVE448
self.curves.update(dict.fromkeys(self.curve448_names, curve448))
else:
raise ValueError("Unsupported curve '%s'" % name)
return self.curves[name]
Expand All @@ -99,12 +107,13 @@ def __getitem__(self, name):
curve = self.curves.get(name)
if curve is None:
curve = self.load(name)
if name in self.curve25519_names:
if name in self.curve25519_names or name in self.curve448_names:
curve.G = EccXPoint(curve.Gx, name)
else:
curve.G = EccPoint(curve.Gx, curve.Gy, name)
curve.is_edwards = curve.id in (CurveID.ED25519, CurveID.ED448)
curve.is_montgomery = curve.id in (CurveID.CURVE25519,)
curve.is_montgomery = curve.id in (CurveID.CURVE25519,
CurveID.CURVE448)
curve.is_weierstrass = not (curve.is_edwards or
curve.is_montgomery)
return curve
Expand Down Expand Up @@ -354,22 +363,30 @@ def __init__(self, x, curve):
raise ValueError("Unknown curve name %s" % str(curve))
self.curve = self._curve.canonical

if self._curve.id != CurveID.CURVE25519:
raise ValueError("EccXPoint can only be created for Curve25519")
if self._curve.id not in (CurveID.CURVE25519, CurveID.CURVE448):
raise ValueError("EccXPoint can only be created for Curve25519/Curve448")

modulus_bytes = self.size_in_bytes()

xb = long_to_bytes(x, modulus_bytes)
if len(xb) != modulus_bytes:
raise ValueError("Incorrect coordinate length")
if x is not None:
xb = c_uint8_ptr(long_to_bytes(x, modulus_bytes))
if len(xb) != modulus_bytes:
raise ValueError("Incorrect coordinate length")

new_point = self._curve.rawlib.new_point
free_func = self._curve.rawlib.free_point

self._point = VoidPointer()
try:
context = self._curve.context.get()
except AttributeError:
context = null_pointer

self._point = VoidPointer()
result = new_point(self._point.address_of(),
c_uint8_ptr(xb),
c_size_t(modulus_bytes))
c_uint8_ptr(xb) if x is not None else null_pointer,
c_size_t(modulus_bytes),
context)

if result == 15:
raise ValueError("The EC point does not belong to the curve")
Expand Down Expand Up @@ -424,7 +441,7 @@ def is_point_at_infinity(self):
def point_at_infinity(self):
"""Return the *point-at-infinity* for the curve."""

return EccXPoint(self._curve.Gx, self.curve) * 0
return EccXPoint(None, self.curve)

@property
def x(self):
Expand Down
9 changes: 7 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,21 +451,26 @@ def create_cryptodome_lib():
sources=['src/curve25519.c'],
py_limited_api=True,
),
Extension("Crypto.PublicKey._curve448",
include_dirs=['src/'],
sources=['src/curve448.c', 'src/mont1.c'],
py_limited_api=True,
),
Extension("Crypto.PublicKey._ed25519",
include_dirs=['src/'],
sources=['src/ed25519.c'],
py_limited_api=True,
),
Extension("Crypto.PublicKey._ed448",
include_dirs=['src/'],
sources=['src/ed448.c', 'src/mont1.c'],
sources=['src/ed448.c', 'src/mont2.c'],
py_limited_api=True,
),

# Math
Extension("Crypto.Math._modexp",
include_dirs=['src/'],
sources=['src/modexp.c', 'src/mont2.c'],
sources=['src/modexp.c', 'src/mont3.c'],
py_limited_api=True,
),
]
Expand Down
7 changes: 5 additions & 2 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ CFLAGS=-Werror -Wall -O3 -g -Wno-unused-const-variable -Wconversion -Wsign-conve

CFLAGS += -fanalyzer

all:: modexp ec_ws_p256 ec_ws_p384 ec_ws_p521 ed25519_perf ed448_perf curve25519_perf
all:: modexp ec_ws_p256 ec_ws_p384 ec_ws_p521 ed25519_perf ed448_perf curve25519_perf curve448_perf

ec_ws_p256: ec_ws_p256.c mont.c p256_table.c p384_table.c p521_table.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ -DSYS_BITS=64 -DMAIN
Expand Down Expand Up @@ -39,5 +39,8 @@ p521_table.c: make_ecc_table.py
curve25519_perf: curve25519.c multiply_64.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ -DSYS_BITS=64 -DPROFILE

curve448_perf: curve448.c mont.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ -DSYS_BITS=64 -DPROFILE

clean::
rm -f ec_ws_p256 ec_ws_p384 ec_ws_p521 mont.o modexp x25519 ed25519_perf ed448_perf curve25519_perf
rm -f ec_ws_p256 ec_ws_p384 ec_ws_p521 mont.o modexp x25519 ed25519_perf ed448_perf curve25519_perf curve448_perf
19 changes: 14 additions & 5 deletions src/curve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,20 +154,29 @@ STATIC void curve25519_scalar_internal(Point *Pout,

EXPORT_SYM int curve25519_new_point(Point **out,
const uint8_t x[32],
size_t modsize)
size_t modsize,
const void *context)
{
if ((NULL == out) || (NULL == x))
if (NULL == out)
return ERR_NULL;

if (modsize != 32)
if (context != NULL)
return ERR_UNKNOWN;

if ((modsize != 32) && (modsize != 0))
return ERR_MODULUS;

*out = calloc(1, sizeof(Point));
if (NULL == *out)
return ERR_MEMORY;

convert_be8_to_le25p5((*out)->X, x);
(*out)->Z[0] = 1;
if ((x != NULL) && (modsize == 32)) {
convert_be8_to_le25p5((*out)->X, x);
(*out)->Z[0] = 1;
} else {
/** PAI **/
(*out)->X[0] = 1;
}

/* No need to verify if the point is on the Curve25519 curve */

Expand Down
3 changes: 2 additions & 1 deletion src/curve25519.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ typedef struct Point {

EXPORT_SYM int curve25519_new_point(Point **out,
const uint8_t x[32],
size_t modsize);
size_t modsize,
const void *context);
EXPORT_SYM int curve25519_clone(Point **P, const Point *Q);
EXPORT_SYM void curve25519_free_point(Point *p);
EXPORT_SYM int curve25519_get_x(uint8_t *xb, size_t modsize, const Point *p);
Expand Down
Loading

0 comments on commit 4a84913

Please sign in to comment.