From 785494285b35c84f2924e981685e526bba8e1e5b Mon Sep 17 00:00:00 2001 From: Berry Schoenmakers Date: Mon, 19 Aug 2024 12:41:23 +0200 Subject: [PATCH] Drop Python 3.9 and Numpy 1.23 support. Following release of Numpy 2.1.0. --- .readthedocs.yaml | 2 +- .travis.yml | 8 +++---- README.md | 2 +- docs/conf.py | 2 +- docs/install.rst | 4 ++-- mpyc/__init__.py | 2 +- mpyc/fingroups.py | 51 +++++++++++++++++++++------------------- mpyc/mpctools.py | 2 +- mpyc/numpy.py | 4 ++-- mpyc/statistics.py | 50 ++++----------------------------------- pyproject.toml | 2 +- tests/test_mpctools.py | 2 +- tests/test_statistics.py | 8 +------ 13 files changed, 46 insertions(+), 93 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 4d12d673..1d35fcc4 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,6 @@ python: build: os: ubuntu-22.04 tools: - python: "3.9" + python: "3.10" sphinx: configuration: docs/conf.py diff --git a/.travis.yml b/.travis.yml index 26d0a0a7..1d2f60f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,15 @@ dist: jammy language: python jobs: - - python: 3.9 - env: - - MPYC_NOPRSS=1 - install: pip install numpy==1.23.* gmpy2 uvloop - - python: pypy3.9-7.3.9 - python: 3.10 env: - MPYC_NONUMPY=1 - MPYC_NOGMPY=1 - MPYC_NOUVLOOP=1 + - python: pypy3.10-7.3.16 - python: 3.11 + env: + - MPYC_NOPRSS=1 install: pip install numpy==1.24.* gmpy2 - python: 3.12 install: pip install numpy uvloop diff --git a/README.md b/README.md index 1068933c..5d5f76b3 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ The [MPyC homepage](https://www.win.tue.nl/~berry/mpyc/) has some more info and ## Installation -Pure Python, no dependencies. Python 3.9+ (following [SPEC 0 -- Minimum Supported Dependencies](https://scientific-python.org/specs/spec-0000/)). +Pure Python, no dependencies. Python 3.10+ (following [SPEC 0 -- Minimum Supported Dependencies](https://scientific-python.org/specs/spec-0000/)). Run `pip install .` in the root directory (containing file `pyproject.toml`).\ Or, run `pip install -e .`, if you want to edit the MPyC source files. diff --git a/docs/conf.py b/docs/conf.py index fa3cdc9b..6b0fb44b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ # import os import sys +from mpyc.__init__ import __version__ # sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('..')) @@ -23,7 +24,6 @@ copyright = '2018 - 2024, Berry Schoenmakers' author = 'Berry Schoenmakers' -from mpyc.__init__ import __version__ # The short X.Y version version = __version__ # The full version, including alpha/beta/rc tags diff --git a/docs/install.rst b/docs/install.rst index 01a7d134..32792506 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -1,7 +1,7 @@ MPyC installation ================= -MPyC runs on Windows/Mac/Linux platforms supporting Python 3.9+. +MPyC runs on Windows/Mac/Linux platforms supporting Python 3.10+. There are no hard dependencies on other Python packages. If you first want to try MPyC online, click @@ -59,7 +59,7 @@ See the ``README.md`` files in these directories for more information. Deployment ---------- -Currently Python 3.9+ is the only requirement. +Currently Python 3.10+ is the only requirement. Written in pure Python, without any dependencies, MPyC should run on common Windows/Mac/Linux platforms, including the 32-bit Raspberry Pi, if you like. diff --git a/mpyc/__init__.py b/mpyc/__init__.py index 64eb488e..e29f2712 100644 --- a/mpyc/__init__.py +++ b/mpyc/__init__.py @@ -29,7 +29,7 @@ and statistics (securely mimicking Python’s statistics module). """ -__version__ = '0.10.2' +__version__ = '0.10.3' import os import sys diff --git a/mpyc/fingroups.py b/mpyc/fingroups.py index 23715c22..b80a05c9 100644 --- a/mpyc/fingroups.py +++ b/mpyc/fingroups.py @@ -1056,14 +1056,15 @@ def _EllipticCurve(curvename, coordinates): raise ValueError('invalid curvename') name = f'E({gf.__name__}){curvename}{coordinates}' - if coordinates == 'extended': - base = EdwardsExtended - elif coordinates == 'affine': - base = EdwardsAffine - elif coordinates == 'projective': - base = EdwardsProjective - else: - raise ValueError('invalid coordinates') + match coordinates: + case 'extended': + base = EdwardsExtended + case 'affine': + base = EdwardsAffine + case 'projective': + base = EdwardsProjective + case _: + raise ValueError('invalid coordinates') EC = type(name, (base,), {'__slots__': ()}) EC.field = gf @@ -1097,14 +1098,15 @@ def _EllipticCurve(curvename, coordinates): raise ValueError('invalid curvename') name = f'E({gf.__name__}){curvename}{coordinates}' - if coordinates == 'jacobian': - base = WeierstrassJacobian - elif coordinates == 'affine': - base = WeierstrassAffine - elif coordinates == 'projective': - base = WeierstrassProjective - else: - raise ValueError('invalid coordinates') + match coordinates: + case 'jacobian': + base = WeierstrassJacobian + case 'affine': + base = WeierstrassAffine + case 'projective': + base = WeierstrassProjective + case _: + raise ValueError('invalid coordinates') EC = type(name, (base,), {'__slots__': ()}) EC.field = gf @@ -1128,14 +1130,15 @@ def _EllipticCurve(curvename, coordinates): gf = GF(p) name = f'E({gf.__name__}){curvename}{coordinates}' - if coordinates == 'jacobian': - base = WeierstrassJacobian - elif coordinates == 'affine': - base = WeierstrassAffine - elif coordinates == 'projective': - base = WeierstrassProjective - else: - raise ValueError('invalid coordinates') + match coordinates: + case 'jacobian': + base = WeierstrassJacobian + case 'affine': + base = WeierstrassAffine + case 'projective': + base = WeierstrassProjective + case _: + raise ValueError('invalid coordinates') EC = type(name, (base,), {'__slots__': ()}) EC.field = gf diff --git a/mpyc/mpctools.py b/mpyc/mpctools.py index e8b4f933..df9c8973 100644 --- a/mpyc/mpctools.py +++ b/mpyc/mpctools.py @@ -4,7 +4,7 @@ The alternative implementations can be used as drop-in replacements, however, potentially enhancing the performance when used in secure computations. More specifically, these implementations are aimed at reducing the overall round -complexity, possible at the expense of increasing overall space complexity, +complexity, possibly at the expense of increasing overall space complexity, time complexity, and communication complexity. """ diff --git a/mpyc/numpy.py b/mpyc/numpy.py index 10ef8466..8234ee88 100644 --- a/mpyc/numpy.py +++ b/mpyc/numpy.py @@ -161,8 +161,8 @@ def _item_shape(shape, key): np._matmul_shape = _matmul_shape np._item_shape = _item_shape - if np.lib.NumpyVersion(np.__version__) < '1.23.0': - logging.warning(f'NumPy {np.__version__} not (fully) supported. Upgrade to NumPy 1.23+.') + if np.lib.NumpyVersion(np.__version__) < '1.24.0': + logging.warning(f'NumPy {np.__version__} not (fully) supported. Upgrade to NumPy 1.24+.') except ImportError: del _matmul_shape del _item_shape diff --git a/mpyc/statistics.py b/mpyc/statistics.py index b789cbaa..5db06b51 100644 --- a/mpyc/statistics.py +++ b/mpyc/statistics.py @@ -22,7 +22,6 @@ function in Python's statistics module. """ -import sys from math import fsum, sqrt import statistics from mpyc import asyncoro @@ -506,14 +505,7 @@ def covariance(x, y): sectype = type(x[0]) # all elts of x assumed of same type if not issubclass(sectype, SecureObject): - if sys.version_info.minor >= 10: - return statistics.covariance(x, y) - - # inline code of statistics.covariance() copied from Python 3.10.0: - xbar = fsum(x) / n - ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - return sxy / (n - 1) + return statistics.covariance(x, y) if issubclass(sectype, SecureFixedPoint): xbar = runtime.sum(x) / n @@ -549,20 +541,7 @@ def correlation(x, y): sectype = type(x[0]) # all elts of x assumed of same type if not issubclass(sectype, SecureObject): - if sys.version_info.minor >= 10: - return statistics.correlation(x, y) - - # inline code of statistics.correlation() copied from Python 3.10.0: - xbar = fsum(x) / n - ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((xi - xbar) ** 2.0 for xi in x) - syy = fsum((yi - ybar) ** 2.0 for yi in y) - try: - return sxy / sqrt(sxx * syy) - - except ZeroDivisionError: - raise statistics.StatisticsError('at least one of the inputs is constant') from None + return statistics.correlation(x, y) if issubclass(sectype, SecureFixedPoint): xbar = runtime.sum(x) / n @@ -577,13 +556,6 @@ def correlation(x, y): raise TypeError('secure fixed-point type required') -if sys.version_info.minor >= 10: - LinearRegression = statistics.LinearRegression -else: - from collections import namedtuple - LinearRegression = namedtuple('LinearRegression', ('slope', 'intercept')) - - def linear_regression(x, y): """Return a (simple) linear regression model for x and y. @@ -610,21 +582,7 @@ def linear_regression(x, y): sectype = type(x[0]) # all elts of x assumed of same type if not issubclass(sectype, SecureObject): - if sys.version_info.minor >= 10: - return statistics.linear_regression(x, y) - - # inline code of statistics.linear_regression() adapted from Python 3.10.0: - xbar = fsum(x) / n - ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((xi - xbar) ** 2.0 for xi in x) - try: - slope = sxy / sxx # equivalent to: covariance(x, y) / variance(x) - except ZeroDivisionError: - raise statistics.StatisticsError('x is constant') from None - - intercept = ybar - slope * xbar - return LinearRegression(slope=slope, intercept=intercept) + return statistics.linear_regression(x, y) if issubclass(sectype, SecureFixedPoint): xbar = runtime.sum(x) / n @@ -635,7 +593,7 @@ def linear_regression(x, y): sxx = runtime.in_prod(xxbar, xxbar) slope = sxy / sxx intercept = ybar - slope * xbar - return LinearRegression(slope=slope, intercept=intercept) + return statistics.LinearRegression(slope=slope, intercept=intercept) # TODO: implement for secure integers as well raise TypeError('secure fixed-point type required') diff --git a/pyproject.toml b/pyproject.toml index 400d2c01..0839c526 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ classifiers = [ 'Topic :: System :: Distributed Computing' ] license = {text = 'MIT License'} -requires-python = '>=3.9' +requires-python = '>=3.10' [project.urls] documentation = 'https://mpyc.readthedocs.io' diff --git a/tests/test_mpctools.py b/tests/test_mpctools.py index 359ab95d..4d4dab41 100644 --- a/tests/test_mpctools.py +++ b/tests/test_mpctools.py @@ -1,7 +1,7 @@ -import unittest import operator import itertools import functools +import unittest from mpyc.runtime import mpc import mpyc.mpctools diff --git a/tests/test_statistics.py b/tests/test_statistics.py index 9a5b6133..18cde2fd 100644 --- a/tests/test_statistics.py +++ b/tests/test_statistics.py @@ -1,17 +1,11 @@ -import sys -import unittest import random import statistics +import unittest from mpyc.runtime import mpc from mpyc.statistics import (mean, variance, stdev, pvariance, pstdev, mode, median, median_low, median_high, quantiles, covariance, correlation, linear_regression) -if sys.version_info.minor < 10: - statistics.covariance = covariance - statistics.correlation = correlation - statistics.linear_regression = linear_regression - class Arithmetic(unittest.TestCase):