From 64929127d1d6ee232b3c2ddf8ef0f06c3e2abf05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 13:46:20 +0000 Subject: [PATCH 1/8] fix: fixing testing infrastructure fail --- examples/linear_regression/src/determinant.py | 2 +- .../linear_regression/src/gauss_jordan.py | 2 +- .../src/linear_regression.py | 2 +- .../src/linear_regression_256.py | 6 ++-- .../linear_regression/src/matrix_inverse.py | 2 +- .../linear_regression/src/modular_inverse.py | 2 +- nada_numpy/array.py | 6 ++-- nada_numpy/types.py | 4 +-- .../src/cleartext_matrix_inverse.ipynb | 2 +- tests/nada-tests/src/gauss_jordan.py | 2 +- tests/nada-tests/src/matrix_inverse.py | 4 +-- tests/nada-tests/src/private_inverse.py | 2 +- tests/nada-tests/src/reveal.py | 8 ++--- .../src/secret_rational_arithmetic.py | 2 +- .../nada-tests/src/unsigned_matrix_inverse.py | 2 +- tests/test_all.py | 29 +++++++++++++++---- 16 files changed, 47 insertions(+), 30 deletions(-) diff --git a/examples/linear_regression/src/determinant.py b/examples/linear_regression/src/determinant.py index 6671125..83196f2 100644 --- a/examples/linear_regression/src/determinant.py +++ b/examples/linear_regression/src/determinant.py @@ -38,7 +38,7 @@ def nada_main(): parties = na.parties(3) X = na.array([3, 3], parties[0], "A", SecretInteger) - X = X.reveal() + X = X.to_public() detX = determinant(X) return na.output(detX, parties[2], "my_output") diff --git a/examples/linear_regression/src/gauss_jordan.py b/examples/linear_regression/src/gauss_jordan.py index 1e026c5..f93611d 100644 --- a/examples/linear_regression/src/gauss_jordan.py +++ b/examples/linear_regression/src/gauss_jordan.py @@ -51,7 +51,7 @@ def nada_main(): A = na.array([3, 3], parties[0], "A", nada_type=SecretInteger) - A = A.reveal() + A = A.to_public() A_inv = gauss_jordan_zn(A, PRIME) outputs = na.output(A_inv, parties[2], "my_output") diff --git a/examples/linear_regression/src/linear_regression.py b/examples/linear_regression/src/linear_regression.py index a98ab52..aadd07c 100644 --- a/examples/linear_regression/src/linear_regression.py +++ b/examples/linear_regression/src/linear_regression.py @@ -91,7 +91,7 @@ def linsol(A: NadaArray, b: NadaArray, modulo: int): ) # (n, n) random matrix R with inverse determinant detR_inv # Revealing matrix RA - RA = (R @ A).reveal() # (n, n) revealed matrix + RA = (R @ A).to_public() # (n, n) revealed matrix # Computing Rb as a secret matrix multiplication of R and b Rb = R @ b # (n, n) @ (n,) = (n,) diff --git a/examples/linear_regression/src/linear_regression_256.py b/examples/linear_regression/src/linear_regression_256.py index aeba8da..d5c6a09 100644 --- a/examples/linear_regression/src/linear_regression_256.py +++ b/examples/linear_regression/src/linear_regression_256.py @@ -56,7 +56,7 @@ def private_modular_inverse(secret: SecretInteger, modulo: int) -> SecretInteger r = SecretInteger.random() ra = r * secret # Masking our secret - ra_revealed = ra.reveal() # Revealing the masked secret + ra_revealed = ra.to_public() # Revealing the masked secret ra_inv = public_modular_inverse( ra_revealed, modulo @@ -144,7 +144,7 @@ def matrix_inverse(matrix: np.ndarray, modulo: int): n = matrix.shape[0] R, detR = random_lu_matrix(n) # n by n random matrix R with determinant detR # Revealing matrix RA - RA = (R @ matrix).reveal() + RA = (R @ matrix).to_public() # # Concatenating RA and R RAR = RA.hstack(R) # Performing Gauss-Jordan elimination @@ -241,7 +241,7 @@ def linsol(A: NadaArray, b: NadaArray, modulo: int): ) # (n, n) random matrix R with inverse determinant detR_inv # Revealing matrix RA - RA = (R @ A).reveal() # (n, n) revealed matrix + RA = (R @ A).to_public() # (n, n) revealed matrix # Computing Rb as a secret matrix multiplication of R and b Rb = R @ b # (n, n) @ (n,) = (n,) diff --git a/examples/linear_regression/src/matrix_inverse.py b/examples/linear_regression/src/matrix_inverse.py index a759ea9..fa63b24 100644 --- a/examples/linear_regression/src/matrix_inverse.py +++ b/examples/linear_regression/src/matrix_inverse.py @@ -168,7 +168,7 @@ def matrix_inverse(matrix: np.ndarray, modulo: int): R, detR = random_lu_matrix(n) # n by n random matrix R with determinant detR # Revealing matrix RA - RA = (R @ matrix).reveal() + RA = (R @ matrix).to_public() # # Concatenating RA and R RAR = RA.hstack(R) # Performing Gauss-Jordan elimination diff --git a/examples/linear_regression/src/modular_inverse.py b/examples/linear_regression/src/modular_inverse.py index 6e16574..8e0a9d5 100644 --- a/examples/linear_regression/src/modular_inverse.py +++ b/examples/linear_regression/src/modular_inverse.py @@ -55,7 +55,7 @@ def private_modular_inverse(secret: SecretInteger, modulo: int) -> SecretInteger r = SecretInteger.random() ra = r * secret # Masking our secret - ra_revealed = ra.reveal() # Revealing the masked secret + ra_revealed = ra.to_public() # Revealing the masked secret ra_inv = public_modular_inverse( ra_revealed, modulo diff --git a/nada_numpy/array.py b/nada_numpy/array.py index 0dc3b0f..680e1f9 100644 --- a/nada_numpy/array.py +++ b/nada_numpy/array.py @@ -550,14 +550,14 @@ def vstack(self, other: "NadaArray") -> "NadaArray": """ return NadaArray(np.vstack((self.inner, other.inner))) - def reveal(self) -> "NadaArray": + def to_public(self) -> "NadaArray": """ - Reveal the elements of the array. + Reveal the elements of the array and make them public Returns: NadaArray: A new NadaArray with revealed values. """ - return self.apply(lambda x: x.reveal()) + return self.apply(lambda x: x.to_public()) def apply(self, func: Callable[[Any], Any]) -> "NadaArray": """ diff --git a/nada_numpy/types.py b/nada_numpy/types.py index 2134c1a..fd1016f 100644 --- a/nada_numpy/types.py +++ b/nada_numpy/types.py @@ -1780,14 +1780,14 @@ def public_equals(self, other: _NadaRational) -> PublicBoolean: raise ValueError("Cannot compare values with different scales.") return self.value.public_equals(other.value) - def reveal(self) -> Rational: + def to_public(self) -> Rational: """ Reveal the SecretRational value. Returns: Rational: Revealed SecretRational value. """ - return Rational(self.value.reveal(), self.log_scale) + return Rational(self.value.to_public(), self.log_scale) def trunc_pr(self, arg_0: _NadaRational) -> "SecretRational": """ diff --git a/tests/nada-tests/src/cleartext_matrix_inverse.ipynb b/tests/nada-tests/src/cleartext_matrix_inverse.ipynb index b6f7346..edd7b98 100644 --- a/tests/nada-tests/src/cleartext_matrix_inverse.ipynb +++ b/tests/nada-tests/src/cleartext_matrix_inverse.ipynb @@ -102,7 +102,7 @@ " np.ndarray: A NumPy array with the revealed values.\n", " \"\"\"\n", " if len(array.shape) == 1:\n", - " return np.array([v.reveal() for v in array])\n", + " return np.array([v.to_public() for v in array])\n", " return np.array([reveal_array(array[i]) for i in range(array.shape[0])])\n", "\n", "\n", diff --git a/tests/nada-tests/src/gauss_jordan.py b/tests/nada-tests/src/gauss_jordan.py index 5b3862c..8021e60 100644 --- a/tests/nada-tests/src/gauss_jordan.py +++ b/tests/nada-tests/src/gauss_jordan.py @@ -86,7 +86,7 @@ def nada_main(): A = na.array([3, 3], parties[0], "A", nada_type=SecretUnsignedInteger) - A = A.reveal() + A = A.to_public() A_inv = gauss_jordan_zn(A, PRIME) outputs = na.output(A_inv, parties[2], "my_output") diff --git a/tests/nada-tests/src/matrix_inverse.py b/tests/nada-tests/src/matrix_inverse.py index 464c881..bafcefc 100644 --- a/tests/nada-tests/src/matrix_inverse.py +++ b/tests/nada-tests/src/matrix_inverse.py @@ -49,7 +49,7 @@ def private_modular_inverse( r = SecretUnsignedInteger.random() ra = r * secret # Masking our secret - ra_revealed = ra.reveal() # Revealing the masked secret + ra_revealed = ra.to_public() # Revealing the masked secret ra_inv = public_modular_inverse( ra_revealed, modulo @@ -140,7 +140,7 @@ def matrix_inverse(matrix: np.ndarray, modulo: int): n = matrix.shape[0] R, detR = random_lu_matrix(n) # n by n random matrix R with determinant detR # Revealing matrix RA - RA = (R @ matrix).reveal() + RA = (R @ matrix).to_public() # # Concatenating RA and R RAR = RA.hstack(R) # Performing Gauss-Jordan elimination diff --git a/tests/nada-tests/src/private_inverse.py b/tests/nada-tests/src/private_inverse.py index 1b4b6cf..1aebf6b 100644 --- a/tests/nada-tests/src/private_inverse.py +++ b/tests/nada-tests/src/private_inverse.py @@ -49,7 +49,7 @@ def private_modular_inverse( r = SecretUnsignedInteger.random() ra = r * secret # Masking our secret - ra_revealed = ra.reveal() # Revealing the masked secret + ra_revealed = ra.to_public() # Revealing the masked secret ra_inv = public_modular_inverse( ra_revealed, modulo diff --git a/tests/nada-tests/src/reveal.py b/tests/nada-tests/src/reveal.py index c7c1129..67e52df 100644 --- a/tests/nada-tests/src/reveal.py +++ b/tests/nada-tests/src/reveal.py @@ -11,8 +11,8 @@ def nada_main(): a = na.array([3, 3], parties[0], "A", SecretInteger) b = na.array([3, 3], parties[1], "B", na.SecretRational) - c = a.reveal() - d = b.reveal() + c = a.to_public() + d = b.to_public() assert c.dtype == NadaInteger, c.dtype assert c.shape == a.shape @@ -21,9 +21,9 @@ def nada_main(): assert d.shape == b.shape with pytest.raises(Exception): - c.reveal() + c.to_public() with pytest.raises(Exception): - d.reveal() + d.to_public() return na.output(c, parties[2], "my_output_A") + na.output( d, parties[2], "my_output_B" diff --git a/tests/nada-tests/src/secret_rational_arithmetic.py b/tests/nada-tests/src/secret_rational_arithmetic.py index 1e0dde3..61e2a70 100644 --- a/tests/nada-tests/src/secret_rational_arithmetic.py +++ b/tests/nada-tests/src/secret_rational_arithmetic.py @@ -27,7 +27,7 @@ def nada_main(): # out_10 = a << UnsignedInteger(1) # out_11 = a >> UnsignedInteger(1) - out_12 = a.reveal() + out_12 = a.to_public() # These for now do not make much sense for users # out_13 = a.trunc_pr(Integer(0)) diff --git a/tests/nada-tests/src/unsigned_matrix_inverse.py b/tests/nada-tests/src/unsigned_matrix_inverse.py index cb24bde..53fb628 100644 --- a/tests/nada-tests/src/unsigned_matrix_inverse.py +++ b/tests/nada-tests/src/unsigned_matrix_inverse.py @@ -113,7 +113,7 @@ def matrix_inverse(matrix: np.ndarray, modulo: int): n = matrix.shape[0] R, detR = random_lu_matrix(n) # n by n random matrix R with determinant detR # Revealing matrix RA - RA = (R @ matrix).reveal() + RA = (R @ matrix).to_public() # # Concatenating RA and R RAR = RA.hstack(R) # Performing Gauss-Jordan elimination diff --git a/tests/test_all.py b/tests/test_all.py index abfbc9d..62f361a 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -5,6 +5,7 @@ TESTS = [ "base", + "new_array", "dot_product", "sum", "broadcasting_sum", @@ -46,6 +47,8 @@ "type_guardrails", "shape", "get_vec", + "determinant", + "linear_regression_256", # Not supported yet # "unsigned_matrix_inverse", "private_inverse", @@ -55,18 +58,29 @@ "fxpmath_methods", "shuffle", "array_comparison", + "private_inverse", ] EXAMPLES = [ - "dot_product", - "matrix_multiplication", - "broadcasting", - "rational_numbers", - "linear_regression", + ("dot_product", "dot_product"), + ("matrix_multiplication", "matrix_multiplication"), + ("broadcasting", "broadcasting"), + ("rational_numbers", "rational_numbers"), + ("linear_regression", "determinant_1"), + ("linear_regression", "determinant_2"), + ("linear_regression", "determinant_3"), + ("linear_regression", "gauss_jordan"), + ("linear_regression", "matrix_inverse"), + ("linear_regression", "linear_regression"), + ("linear_regression", "linear_regression_1"), + ("linear_regression", "linear_regression_2"), + ("linear_regression", "linear_regression_256_1"), + ("linear_regression", "linear_regression_256_2"), + ("linear_regression", "modular_inverse"), ] TESTS = [("tests/nada-tests/", test) for test in TESTS] + [ - (os.path.join("examples/", test), test) for test in EXAMPLES + (os.path.join("examples/", test[0]), test[1]) for test in EXAMPLES ] @@ -81,6 +95,9 @@ def build_nada(test_dir): ["nada", "build", test_dir[1]], cwd=test_dir[0], capture_output=True, text=True ) err = result.stderr.lower() + result.stdout.lower() + if test_dir[1] == "determinant" and test_dir[0] == "examples/": + print(err) + raise Exception("Error") if result.returncode != 0 or "error" in err or "fail" in err: pytest.fail(f"Build {test_dir}:\n{result.stdout + result.stderr}") From 894957996da2cf22a8c1d76a60b3ff3f3c90d469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 14:18:04 +0000 Subject: [PATCH 2/8] fix: more fixes to tests --- nada_numpy/types.py | 4 +++- tests/nada-tests/src/new_array.py | 2 +- tests/nada-tests/src/shuffle.py | 39 ++++++++++++++++++------------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/nada_numpy/types.py b/nada_numpy/types.py index fd1016f..f5dbc4d 100644 --- a/nada_numpy/types.py +++ b/nada_numpy/types.py @@ -169,6 +169,7 @@ def __init__( if not isinstance(value, (Integer, PublicInteger)): raise TypeError(f"Cannot instantiate Rational from type `{type(value)}`.") + self.base_type = "Rational" if log_scale is None: log_scale = get_log_scale() self._log_scale = log_scale @@ -1299,6 +1300,7 @@ def __init__( f"Cannot instantiate SecretRational from type `{type(value)}`." ) + self.base_type = "Rational" if log_scale is None: log_scale = get_log_scale() self._log_scale = log_scale @@ -1346,7 +1348,7 @@ def add(self, other: _NadaRational, ignore_scale: bool = False) -> "SecretRation SecretRational: Result of the addition. """ if not isinstance(other, (Rational, SecretRational)): - return NotImplemented + return NotImplemented # Lays the groundwork for broadcasting to Nada Array if it implements it if not ignore_scale and self.log_scale != other.log_scale: raise ValueError("Cannot add values with different scales.") diff --git a/tests/nada-tests/src/new_array.py b/tests/nada-tests/src/new_array.py index 906846a..ce519ea 100644 --- a/tests/nada-tests/src/new_array.py +++ b/tests/nada-tests/src/new_array.py @@ -11,7 +11,7 @@ def nada_main(): b = a[0] c = a[0, 0] - assert isinstance(a[0, 0], SecretInteger), "a[0][0] should be a SecretInteger" + assert isinstance(a[0, 0, 0], SecretInteger), "a[0][0] should be a SecretInteger" assert isinstance(a[0], na.NadaArray), "a[0] should be a NadaArray" return a.output(parties[1], "my_output") diff --git a/tests/nada-tests/src/shuffle.py b/tests/nada-tests/src/shuffle.py index 676718d..774346b 100644 --- a/tests/nada-tests/src/shuffle.py +++ b/tests/nada-tests/src/shuffle.py @@ -2,16 +2,18 @@ from typing import List +import numpy as np from nada_dsl import Integer, Output, PublicInteger, SecretInteger -import numpy as np import nada_numpy as na from nada_numpy import shuffle + def bool_to_int(bool): """Casting bool to int""" return bool.if_else(Integer(0), Integer(1)) + def count(vec, element): """ Counts the number of times element is in vec. @@ -24,7 +26,7 @@ def count(vec, element): result += int_b return result - + def nada_main() -> List[Output]: @@ -36,7 +38,6 @@ def nada_main() -> List[Output]: c = na.array([n], parties[0], "C", PublicInteger) d = na.array([n], parties[0], "D", SecretInteger) - # As a function shuffled_a = shuffle(a) @@ -50,24 +51,23 @@ def nada_main() -> List[Output]: result_c = shuffled_c - shuffled_c result_d = shuffled_d - shuffled_d - # 2. Randomness: show at least one element is in a different position + # 2. Randomness: show at least one element is in a different position # true if equal - diff_position_bool = [a[i] == shuffled_a[i] for i in range(n)] + diff_position_bool = [a[i] == shuffled_a[i] for i in range(n)] # cast to int (true -> 0 and false -> 1) - diff_position = np.array([bool_to_int(element) for element in diff_position_bool]) + diff_position = np.array([bool_to_int(element) for element in diff_position_bool]) # add them sum = diff_position.sum() # if all are equal => all are 0 => sum is zero at_least_one_diff_element = sum > Integer(0) - - # 3. Show elements are preserved: + + # 3. Show elements are preserved: check = Integer(0) for ai in a: nr_ai_in_shufled_a = count(shuffled_a, ai) nr_ai_in_a = count(a, ai) check += bool_to_int(nr_ai_in_shufled_a == nr_ai_in_a) elements_are_preserved = check == Integer(0) - # As a method @@ -82,17 +82,19 @@ def nada_main() -> List[Output]: result_method_c = shuffled_method_c - shuffled_method_c result_method_d = shuffled_method_d - shuffled_method_d - # 2. Randomness: show at least one element is in a different position + # 2. Randomness: show at least one element is in a different position # true if equal - diff_position_bool_method = [a[i] == shuffled_method_a[i] for i in range(n)] + diff_position_bool_method = [a[i] == shuffled_method_a[i] for i in range(n)] # cast to int (true -> 0 and false -> 1) - diff_position_method = np.array([bool_to_int(element) for element in diff_position_bool_method]) + diff_position_method = np.array( + [bool_to_int(element) for element in diff_position_bool_method] + ) # add them sum_method = diff_position_method.sum() # if all are equal => all are 0 => sum is zero at_least_one_diff_element_method = sum_method > Integer(0) - # 3. Show elements are preserved: + # 3. Show elements are preserved: check = Integer(0) for ai in a: nr_ai_in_shufled_a = count(shuffled_method_a, ai) @@ -100,7 +102,6 @@ def nada_main() -> List[Output]: check += bool_to_int(nr_ai_in_shufled_a == nr_ai_in_a) elements_are_preserved_method = check == Integer(0) - return ( na.output(result_a, parties[1], "my_output_a") + na.output(result_b, parties[1], "my_output_b") @@ -111,7 +112,13 @@ def nada_main() -> List[Output]: + na.output(result_method_c, parties[1], "my_output_method_c") + na.output(result_method_d, parties[1], "my_output_method_d") + na.output(at_least_one_diff_element, parties[1], "at_least_one_diff_element") - + na.output(at_least_one_diff_element_method, parties[1], "at_least_one_diff_element_method") + + na.output( + at_least_one_diff_element_method, + parties[1], + "at_least_one_diff_element_method", + ) + na.output(elements_are_preserved, parties[1], "elements_are_preserved") - + na.output(elements_are_preserved_method, parties[1], "elements_are_preserved_method") + + na.output( + elements_are_preserved_method, parties[1], "elements_are_preserved_method" + ) ) From 0971330a8ab01f2813dc7054126c579f68572ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 14:18:21 +0000 Subject: [PATCH 3/8] fix: bump version of nada_dsl to work with to_public --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e2b130e..9a4d12a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nada-numpy" -version = "0.5.2" +version = "0.5.3" description = "Nada-Numpy is a Python library designed for algebraic operations on NumPy-like array objects on top of Nada DSL and Nillion Network." authors = ["José Cabrero-Holgueras "] readme = "README.md" @@ -8,7 +8,7 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.10" numpy = "^1.26.4" -nada-dsl = "^0.6.0" +nada-dsl = "^0.6.3" py-nillion-client = "^0.6.0" nillion-python-helpers = "^0.3.0" black = {version="24.8.0", optional=true} From ab224c55f36b7dca1783a2c3cc86f6ba194119ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 14:18:59 +0000 Subject: [PATCH 4/8] fix: linting --- nada_numpy/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nada_numpy/types.py b/nada_numpy/types.py index f5dbc4d..3f47838 100644 --- a/nada_numpy/types.py +++ b/nada_numpy/types.py @@ -1348,7 +1348,7 @@ def add(self, other: _NadaRational, ignore_scale: bool = False) -> "SecretRation SecretRational: Result of the addition. """ if not isinstance(other, (Rational, SecretRational)): - return NotImplemented # Lays the groundwork for broadcasting to Nada Array if it implements it + return NotImplemented # Lays the groundwork for broadcasting to Nada Array if it implements it if not ignore_scale and self.log_scale != other.log_scale: raise ValueError("Cannot add values with different scales.") From 060c6b204ba42372ce3334f989f39ee94b135dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 14:19:35 +0000 Subject: [PATCH 5/8] fix: poetry.lock --- poetry.lock | 70 ++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/poetry.lock b/poetry.lock index 60b3990..84c0a53 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "astroid" -version = "3.2.4" +version = "3.3.4" description = "An abstract syntax tree for Python with inference support." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25"}, - {file = "astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a"}, + {file = "astroid-3.3.4-py3-none-any.whl", hash = "sha256:5eba185467253501b62a9f113c263524b4f5d55e1b30456370eed4cdbd6438fd"}, + {file = "astroid-3.3.4.tar.gz", hash = "sha256:e73d0b62dd680a7c07cb2cd0ce3c22570b044dd01bd994bc3a2dd16c6cbba162"}, ] [package.dependencies] @@ -389,15 +389,18 @@ protobuf = ["grpcio-tools (>=1.66.1)"] [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -540,12 +543,13 @@ files = [ [[package]] name = "nada-dsl" -version = "0.6.0" +version = "0.6.3" description = "Nillion Nada DSL to create Nillion MPC programs." optional = false python-versions = ">=3.10" files = [ - {file = "nada_dsl-0.6.0-py3-none-any.whl", hash = "sha256:dd0484953dc3237bf14987840904fe7bc22d4112e6da679c5f550422ddb0d3ad"}, + {file = "nada_dsl-0.6.3-py3-none-any.whl", hash = "sha256:1fb03c056d9e1e6282ed9d41306ca47544d63f11cfa06df4ec091f53eae43ace"}, + {file = "nada_dsl-0.6.3.tar.gz", hash = "sha256:96748347569ea7e5430ab66d670c40f80d95b70449937380237d3886825249e9"}, ] [package.dependencies] @@ -561,13 +565,13 @@ test = ["pytest (>=7.4,<9.0)", "pytest-cov (>=4,<6)"] [[package]] name = "nillion-python-helpers" -version = "0.3.0" +version = "0.3.1" description = "" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "nillion_python_helpers-0.3.0-py3-none-any.whl", hash = "sha256:93322e0b3dea55bbace01d5a00fe9a295c714e5df90624519a3d4f059e0ad6b1"}, - {file = "nillion_python_helpers-0.3.0.tar.gz", hash = "sha256:ee3fabf614c1305419b939fac4a0334ee3c35f688a0573679d201addc72ea741"}, + {file = "nillion_python_helpers-0.3.1-py3-none-any.whl", hash = "sha256:62bdf0d33c52c0780920dacb66505dd04c3a46325751789919fb0d96ff71de4d"}, + {file = "nillion_python_helpers-0.3.1.tar.gz", hash = "sha256:8ff7b4df2ddc7e8e0354cf6d7a99c0e00163f4f49b4808d9360b8ead7e32bb8c"}, ] [package.dependencies] @@ -663,13 +667,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.3.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"}, - {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] @@ -694,22 +698,22 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "4.25.4" +version = "4.25.5" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4"}, - {file = "protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d"}, - {file = "protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b"}, - {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835"}, - {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040"}, - {file = "protobuf-4.25.4-cp38-cp38-win32.whl", hash = "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1"}, - {file = "protobuf-4.25.4-cp38-cp38-win_amd64.whl", hash = "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1"}, - {file = "protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca"}, - {file = "protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f"}, - {file = "protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978"}, - {file = "protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d"}, + {file = "protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8"}, + {file = "protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea"}, + {file = "protobuf-4.25.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173"}, + {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d"}, + {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331"}, + {file = "protobuf-4.25.5-cp38-cp38-win32.whl", hash = "sha256:98d8d8aa50de6a2747efd9cceba361c9034050ecce3e09136f90de37ddba66e1"}, + {file = "protobuf-4.25.5-cp38-cp38-win_amd64.whl", hash = "sha256:b0234dd5a03049e4ddd94b93400b67803c823cfc405689688f59b34e0742381a"}, + {file = "protobuf-4.25.5-cp39-cp39-win32.whl", hash = "sha256:abe32aad8561aa7cc94fc7ba4fdef646e576983edb94a73381b03c53728a626f"}, + {file = "protobuf-4.25.5-cp39-cp39-win_amd64.whl", hash = "sha256:7a183f592dc80aa7c8da7ad9e55091c4ffc9497b3054452d629bb85fa27c2a45"}, + {file = "protobuf-4.25.5-py3-none-any.whl", hash = "sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41"}, + {file = "protobuf-4.25.5.tar.gz", hash = "sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584"}, ] [[package]] @@ -774,17 +778,17 @@ files = [ [[package]] name = "pylint" -version = "3.2.7" +version = "3.3.1" description = "python code static checker" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "pylint-3.2.7-py3-none-any.whl", hash = "sha256:02f4aedeac91be69fb3b4bea997ce580a4ac68ce58b89eaefeaf06749df73f4b"}, - {file = "pylint-3.2.7.tar.gz", hash = "sha256:1b7a721b575eaeaa7d39db076b6e7743c993ea44f57979127c517c6c572c803e"}, + {file = "pylint-3.3.1-py3-none-any.whl", hash = "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9"}, + {file = "pylint-3.3.1.tar.gz", hash = "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e"}, ] [package.dependencies] -astroid = ">=3.2.4,<=3.3.0-dev0" +astroid = ">=3.3.4,<=3.4.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -1220,4 +1224,4 @@ linter = ["black", "isort"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "ec7986275a21818f581640255226bde2c8711356df648f774863a8cee34c51f1" +content-hash = "988468fb1d039ce86e25f619f2c62893e0baf09176b6341402dc500184baa865" From 0b140b82d5e7e8d18e1a085234110c25e7035470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 14:24:29 +0000 Subject: [PATCH 6/8] fix: linting --- nada_numpy/types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nada_numpy/types.py b/nada_numpy/types.py index 3f47838..399c0de 100644 --- a/nada_numpy/types.py +++ b/nada_numpy/types.py @@ -1348,7 +1348,8 @@ def add(self, other: _NadaRational, ignore_scale: bool = False) -> "SecretRation SecretRational: Result of the addition. """ if not isinstance(other, (Rational, SecretRational)): - return NotImplemented # Lays the groundwork for broadcasting to Nada Array if it implements it + # Lays the groundwork for broadcasting to Nada Array if it implements it + return NotImplemented if not ignore_scale and self.log_scale != other.log_scale: raise ValueError("Cannot add values with different scales.") From 4020e52cab9e317fbc5a39005daa544efbebb0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 15:16:27 +0000 Subject: [PATCH 7/8] fix: more fixes to tests --- ...{determinant-3.yaml => determinant_3.yaml} | 0 nada_numpy/array.py | 2 +- nada_numpy/client.py | 31 ++-------- nada_numpy/funcs.py | 2 +- nada_numpy/types.py | 10 ++-- tests/nada-tests/src/new_array.py | 1 + tests/nada-tests/tests/new_array.yaml | 58 +++++++++++++++++++ tests/test_all.py | 39 ++++++------- 8 files changed, 89 insertions(+), 54 deletions(-) rename examples/linear_regression/tests/{determinant-3.yaml => determinant_3.yaml} (100%) create mode 100644 tests/nada-tests/tests/new_array.yaml diff --git a/examples/linear_regression/tests/determinant-3.yaml b/examples/linear_regression/tests/determinant_3.yaml similarity index 100% rename from examples/linear_regression/tests/determinant-3.yaml rename to examples/linear_regression/tests/determinant_3.yaml diff --git a/nada_numpy/array.py b/nada_numpy/array.py index 680e1f9..5334f8f 100644 --- a/nada_numpy/array.py +++ b/nada_numpy/array.py @@ -1516,7 +1516,7 @@ def log(x): f"Log is not compatible with {dtype}, only with Rational and SecretRational types." ) - def reciprocal( # pylint: disable=too-many-arguments + def reciprocal( # pylint: disable=too-many-arguments disable=too-many-positional-arguments self, all_pos: bool = False, initial: Optional["Rational"] = None, diff --git a/nada_numpy/client.py b/nada_numpy/client.py index 48ee075..4394057 100644 --- a/nada_numpy/client.py +++ b/nada_numpy/client.py @@ -61,36 +61,13 @@ def array( Dict: A dictionary mapping generated names to Nillion input objects. """ # TODO: Use this version when check for zero values is removed - # if len(arr.shape) == 1: - # if nada_type == Rational: - # nada_type = public_rational # type: ignore - # elif nada_type == SecretRational: - # nada_type = secret_rational # type: ignore - # return { - # f"{prefix}_{i}": (nada_type(int(arr[i]))) for i in range(arr.shape[0]) # type: ignore - # } - - # TODO: remove check for zero values when pushing zero secrets is supported - if len(arr.shape) == 1: if nada_type == Rational: - return { - f"{prefix}_{i}": (public_rational(arr[i])) for i in range(arr.shape[0]) - } - if nada_type == SecretRational: - return { - f"{prefix}_{i}": ( - secret_rational(arr[i]) if arr[i] != 0 else SecretInteger(1) - ) - for i in range(arr.shape[0]) - } + nada_type = public_rational # type: ignore + elif nada_type == SecretRational: + nada_type = secret_rational # type: ignore return { - f"{prefix}_{i}": ( - nada_type(int(arr[i])) # type: ignore - if (nada_type in (Integer, UnsignedInteger) or int(arr[i]) != 0) - else nada_type(1) # type: ignore - ) - for i in range(arr.shape[0]) + f"{prefix}_{i}": (nada_type(int(arr[i]))) for i in range(arr.shape[0]) # type: ignore } return { k: v diff --git a/nada_numpy/funcs.py b/nada_numpy/funcs.py index 6c07e6e..dc06087 100644 --- a/nada_numpy/funcs.py +++ b/nada_numpy/funcs.py @@ -730,7 +730,7 @@ def log( ) -def reciprocal( # pylint: disable=too-many-arguments +def reciprocal( # pylint: disable=too-many-arguments disable=too-many-positional-arguments arr: NadaArray, all_pos: bool = False, initial: Optional["Rational"] = None, diff --git a/nada_numpy/types.py b/nada_numpy/types.py index 399c0de..84bf6b8 100644 --- a/nada_numpy/types.py +++ b/nada_numpy/types.py @@ -24,7 +24,7 @@ ] -class SecretBoolean(dsl.SecretBoolean): +class SecretBoolean(dsl.SecretBoolean): # pylint:disable=too-many-ancestors """SecretBoolean rational wrapper""" def __init__(self, value: dsl.SecretBoolean) -> None: @@ -80,7 +80,7 @@ def if_else( return result -class PublicBoolean(dsl.PublicBoolean): +class PublicBoolean(dsl.PublicBoolean): # pylint:disable=too-many-ancestors """PublicBoolean rational wrapper""" def __init__(self, value: dsl.PublicBoolean) -> None: @@ -839,7 +839,7 @@ def log( raise TypeError("log input should be of type Rational.") return result - def reciprocal( # pylint: disable=too-many-arguments + def reciprocal( # pylint: disable=too-many-arguments disable=too-many-positional-arguments self, all_pos: bool = False, initial: Optional["Rational"] = None, @@ -1975,7 +1975,7 @@ def log( raise TypeError("log input should be of type SecretRational.") return result - def reciprocal( # pylint: disable=too-many-arguments + def reciprocal( # pylint: disable=too-many-arguments disable=too-many-positional-arguments self, all_pos: bool = False, initial: Optional["Rational"] = None, @@ -2673,7 +2673,7 @@ def log( return y -def reciprocal( # pylint: disable=too-many-arguments +def reciprocal( # pylint: disable=too-many-arguments disable=too-many-positional-arguments x: _NadaRational, all_pos: bool = False, initial: Optional[Rational] = None, diff --git a/tests/nada-tests/src/new_array.py b/tests/nada-tests/src/new_array.py index ce519ea..9f153d3 100644 --- a/tests/nada-tests/src/new_array.py +++ b/tests/nada-tests/src/new_array.py @@ -14,4 +14,5 @@ def nada_main(): assert isinstance(a[0, 0, 0], SecretInteger), "a[0][0] should be a SecretInteger" assert isinstance(a[0], na.NadaArray), "a[0] should be a NadaArray" + a += Integer(0) return a.output(parties[1], "my_output") diff --git a/tests/nada-tests/tests/new_array.yaml b/tests/nada-tests/tests/new_array.yaml new file mode 100644 index 0000000..c1701a2 --- /dev/null +++ b/tests/nada-tests/tests/new_array.yaml @@ -0,0 +1,58 @@ +--- +program: new_array +inputs: + A_0_0_0: 3 + A_0_0_1: 3 + A_0_0_2: 3 + A_0_1_0: 3 + A_0_1_1: 3 + A_0_1_2: 3 + A_0_2_0: 3 + A_0_2_1: 3 + A_0_2_2: 3 + A_1_0_0: 3 + A_1_0_1: 3 + A_1_0_2: 3 + A_1_1_0: 3 + A_1_1_1: 3 + A_1_1_2: 3 + A_1_2_0: 3 + A_1_2_1: 3 + A_1_2_2: 3 + A_2_0_0: 3 + A_2_0_1: 3 + A_2_0_2: 3 + A_2_1_0: 3 + A_2_1_1: 3 + A_2_1_2: 3 + A_2_2_0: 3 + A_2_2_1: 3 + A_2_2_2: 3 +expected_outputs: + my_output_0_0_0: 3 + my_output_0_0_1: 3 + my_output_0_0_2: 3 + my_output_0_1_0: 3 + my_output_0_1_1: 3 + my_output_0_1_2: 3 + my_output_0_2_0: 3 + my_output_0_2_1: 3 + my_output_0_2_2: 3 + my_output_1_0_0: 3 + my_output_1_0_1: 3 + my_output_1_0_2: 3 + my_output_1_1_0: 3 + my_output_1_1_1: 3 + my_output_1_1_2: 3 + my_output_1_2_0: 3 + my_output_1_2_1: 3 + my_output_1_2_2: 3 + my_output_2_0_0: 3 + my_output_2_0_1: 3 + my_output_2_0_2: 3 + my_output_2_1_0: 3 + my_output_2_1_1: 3 + my_output_2_1_2: 3 + my_output_2_2_0: 3 + my_output_2_2_1: 3 + my_output_2_2_2: 3 diff --git a/tests/test_all.py b/tests/test_all.py index 62f361a..db9639d 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -47,8 +47,6 @@ "type_guardrails", "shape", "get_vec", - "determinant", - "linear_regression_256", # Not supported yet # "unsigned_matrix_inverse", "private_inverse", @@ -62,25 +60,26 @@ ] EXAMPLES = [ - ("dot_product", "dot_product"), - ("matrix_multiplication", "matrix_multiplication"), - ("broadcasting", "broadcasting"), - ("rational_numbers", "rational_numbers"), - ("linear_regression", "determinant_1"), - ("linear_regression", "determinant_2"), - ("linear_regression", "determinant_3"), - ("linear_regression", "gauss_jordan"), - ("linear_regression", "matrix_inverse"), - ("linear_regression", "linear_regression"), - ("linear_regression", "linear_regression_1"), - ("linear_regression", "linear_regression_2"), - ("linear_regression", "linear_regression_256_1"), - ("linear_regression", "linear_regression_256_2"), - ("linear_regression", "modular_inverse"), + # FORMAT: (EXAMPLES_DIR (DIR), EXAMPLE_NAME (PY), TEST_NAME (YAML)) + ("dot_product", "dot_product", "dot_product"), + ("matrix_multiplication", "matrix_multiplication", "matrix_multiplication"), + ("broadcasting", "broadcasting", "broadcasting"), + ("rational_numbers", "rational_numbers", "rational_numbers"), + ("linear_regression", "determinant", "determinant_1"), + ("linear_regression", "determinant", "determinant_2"), + ("linear_regression", "determinant", "determinant_3"), + ("linear_regression", "gauss_jordan", "gauss_jordan"), + ("linear_regression", "matrix_inverse", "matrix_inverse"), + ("linear_regression", "linear_regression", "linear_regression"), + ("linear_regression", "linear_regression", "linear_regression_1"), + ("linear_regression", "linear_regression", "linear_regression_2"), + ("linear_regression", "linear_regression", "linear_regression_256_1"), + ("linear_regression", "linear_regression", "linear_regression_256_2"), + ("linear_regression", "modular_inverse", "modular_inverse"), ] -TESTS = [("tests/nada-tests/", test) for test in TESTS] + [ - (os.path.join("examples/", test[0]), test[1]) for test in EXAMPLES +TESTS = [("tests/nada-tests/", test, test) for test in TESTS] + [ + (os.path.join("examples/", test[0]), test[1], test[2]) for test in EXAMPLES ] @@ -104,7 +103,7 @@ def build_nada(test_dir): def run_nada(test_dir): result = subprocess.run( - ["nada", "test", test_dir[1]], cwd=test_dir[0], capture_output=True, text=True + ["nada", "test", test_dir[2]], cwd=test_dir[0], capture_output=True, text=True ) # if "shape" in test_dir[1]: From 118eb5989cb1fb9ca0400b9de7d7cd5fe02d4241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 17:32:56 +0000 Subject: [PATCH 8/8] feat: working matrix inverse (not integrated) --- examples/linear_regression/nada-project.toml | 3 + .../linear_regression/src/matrix_inverse.py | 13 +--- .../linear_regression/tests/matrix_inverse.py | 24 +++++++ .../tests/matrix_inverse.yaml | 62 ------------------- poetry.lock | 15 ++++- pyproject.toml | 1 + tests/test_all.py | 2 +- 7 files changed, 46 insertions(+), 74 deletions(-) create mode 100644 examples/linear_regression/tests/matrix_inverse.py delete mode 100644 examples/linear_regression/tests/matrix_inverse.yaml diff --git a/examples/linear_regression/nada-project.toml b/examples/linear_regression/nada-project.toml index 1d8d8af..afd7966 100644 --- a/examples/linear_regression/nada-project.toml +++ b/examples/linear_regression/nada-project.toml @@ -2,6 +2,9 @@ name = "linear-regression" version = "0.1.0" authors = [""] +[test_framework.nada-test] +command = "nada-test ./tests" + [[programs]] path = "src/linear_regression.py" prime_size = 64 diff --git a/examples/linear_regression/src/matrix_inverse.py b/examples/linear_regression/src/matrix_inverse.py index fa63b24..8e50d01 100644 --- a/examples/linear_regression/src/matrix_inverse.py +++ b/examples/linear_regression/src/matrix_inverse.py @@ -40,7 +40,7 @@ def public_modular_inverse( power = value ** Integer( mod - 1 ) # value ** modulo = value ** (modulo // 2) * modulo ** (modulo // 2) - power = power * power * value if rem else Integer(1) # value ** mo + power = power * power * (value if rem else Integer(1)) # value ** mo return power @@ -133,14 +133,7 @@ def gauss_jordan_zn(mat: na.NadaArray, modulo: int): # Forward elimination for i in range(rows): - # # Find pivot row - # pivot_row = i - # while pivot_row < rows and (mat[pivot_row][i] == Integer(0)) is Boolean(True): - # pivot_row += 1 - - # # Swap pivot row with current row - # mat[[i, pivot_row]] = mat[[pivot_row, i]] - + # Scale pivot row to have leading 1 diagonal_element = mat[i][i] pivot_inv = public_modular_inverse(diagonal_element, modulo) @@ -186,7 +179,7 @@ def matrix_inverse(matrix: np.ndarray, modulo: int): def nada_main(): parties = na.parties(3) - A = na.array([4, 4], parties[0], "A", nada_type=SecretInteger) + A = na.array([10, 10], parties[0], "A", nada_type=SecretInteger) A_inv = matrix_inverse(A, PRIME) result = A @ A_inv diff --git a/examples/linear_regression/tests/matrix_inverse.py b/examples/linear_regression/tests/matrix_inverse.py new file mode 100644 index 0000000..9ab7832 --- /dev/null +++ b/examples/linear_regression/tests/matrix_inverse.py @@ -0,0 +1,24 @@ +from nada_test import nada_test, NadaTest +import sys +import nada_numpy.client as na +import numpy as np + +# Functional style test +@nada_test(program="matrix_inverse") +def my_test(): + n = 10 + m = np.random.rand(n, n) + mx = np.sum(np.abs(m), axis=1) + np.fill_diagonal(m, mx) + A = na.array(m * (1 << 16), "A", nada_type=int) + print("INPUTS:", A, file=sys.stderr) + outputs = yield A + print(outputs, file=sys.stderr) + for output, value in outputs.items(): + output = output.split("_") + if output[-1] == output[-2]: + assert value == 1, f"Expected 1 {output}, got {value}" + else: + assert value == 0, f"Expected 0 {output}, got {value}" + + #assert outputs["my_output"] == a + b \ No newline at end of file diff --git a/examples/linear_regression/tests/matrix_inverse.yaml b/examples/linear_regression/tests/matrix_inverse.yaml deleted file mode 100644 index 1d5968b..0000000 --- a/examples/linear_regression/tests/matrix_inverse.yaml +++ /dev/null @@ -1,62 +0,0 @@ -program: matrix_inverse -inputs: - A_0_0: -256 - A_0_1: 256 - A_0_2: -251 - A_0_3: 158 - A_0_4: 141 - A_0_5: -212 - A_1_0: 121 - A_1_1: -7 - A_1_2: -6 - A_1_3: -29 - A_1_4: 51 - A_1_5: 163 - A_2_0: 227 - A_2_1: 19 - A_2_2: -150 - A_2_3: 43 - A_2_4: -136 - A_2_5: 157 - A_3_0: 101 - A_3_1: 190 - A_3_2: -178 - A_3_3: 59 - A_3_4: 204 - A_3_5: -194 - A_4_0: -252 - A_4_1: -45 - A_4_2: -9 - A_4_3: 157 - A_4_4: 92 - A_4_5: -149 - A_5_0: -208 - A_5_1: 29 - A_5_2: 60 - A_5_3: 2 - A_5_4: -132 - A_5_5: -54 - b_0: -255 - b_1: -108 - b_2: -183 - b_3: 73 - b_4: -92 - b_5: -65 - B: 456 -expected_outputs: - my_output_0_0: 1 - my_output_0_1: 0 - my_output_0_2: 0 - my_output_0_3: 0 - my_output_1_0: 0 - my_output_1_1: 1 - my_output_1_2: 0 - my_output_1_3: 0 - my_output_2_0: 0 - my_output_2_1: 0 - my_output_2_2: 1 - my_output_2_3: 0 - my_output_3_0: 0 - my_output_3_1: 0 - my_output_3_2: 0 - my_output_3_3: 1 diff --git a/poetry.lock b/poetry.lock index 84c0a53..eab3b84 100644 --- a/poetry.lock +++ b/poetry.lock @@ -563,6 +563,19 @@ docs = ["sphinx (>=5,<9)", "sphinx-rtd-theme (>=1.0,<2.1)", "toml (>=0.10.2,<0.1 lint = ["pylint (>=2.17,<3.3)"] test = ["pytest (>=7.4,<9.0)", "pytest-cov (>=4,<6)"] +[[package]] +name = "nada-test" +version = "0.6.0" +description = "Nillion Nada Test Framework" +optional = false +python-versions = ">=3.10" +files = [ + {file = "nada_test-0.6.0-py3-none-any.whl", hash = "sha256:985bf53411562478684b5869ea0c7c5dfe8e936bf776477338430a20d8cde062"}, +] + +[package.extras] +lint = ["pylint (>=2.17,<3.3)"] + [[package]] name = "nillion-python-helpers" version = "0.3.1" @@ -1224,4 +1237,4 @@ linter = ["black", "isort"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "988468fb1d039ce86e25f619f2c62893e0baf09176b6341402dc500184baa865" +content-hash = "2a8caf5f826dcc51363c5ee9f6c5e82452dfe780d95b2e4e487e3ef61eac32ad" diff --git a/pyproject.toml b/pyproject.toml index 9a4d12a..efae330 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ nillion-python-helpers = "^0.3.0" black = {version="24.8.0", optional=true} isort = {version="^5.13.2", optional=true} scikit-learn = {version="^1.5.1", optional=true} +nada-test = "^0.6.0" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/tests/test_all.py b/tests/test_all.py index db9639d..205de46 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -69,7 +69,7 @@ ("linear_regression", "determinant", "determinant_2"), ("linear_regression", "determinant", "determinant_3"), ("linear_regression", "gauss_jordan", "gauss_jordan"), - ("linear_regression", "matrix_inverse", "matrix_inverse"), + ("linear_regression", "matrix_inverse", "nada-test::matrix_inverse.py:my_test"), ("linear_regression", "linear_regression", "linear_regression"), ("linear_regression", "linear_regression", "linear_regression_1"), ("linear_regression", "linear_regression", "linear_regression_2"),