Skip to content

Commit

Permalink
fix: fixing testing infrastructure fail (#74)
Browse files Browse the repository at this point in the history
* fix: fixing testing infrastructure fail including tests

* feat: working matrix inverse example (not integrated)
  • Loading branch information
jcabrero authored Sep 30, 2024
1 parent e0a8dce commit f3c98b1
Show file tree
Hide file tree
Showing 27 changed files with 228 additions and 190 deletions.
3 changes: 3 additions & 0 deletions examples/linear_regression/nada-project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/linear_regression/src/determinant.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
2 changes: 1 addition & 1 deletion examples/linear_regression/src/gauss_jordan.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
2 changes: 1 addition & 1 deletion examples/linear_regression/src/linear_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,)
Expand Down
6 changes: 3 additions & 3 deletions examples/linear_regression/src/linear_regression_256.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,)
Expand Down
15 changes: 4 additions & 11 deletions examples/linear_regression/src/matrix_inverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -168,7 +161,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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/linear_regression/src/modular_inverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions examples/linear_regression/tests/matrix_inverse.py
Original file line number Diff line number Diff line change
@@ -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
62 changes: 0 additions & 62 deletions examples/linear_regression/tests/matrix_inverse.yaml

This file was deleted.

8 changes: 4 additions & 4 deletions nada_numpy/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
"""
Expand Down Expand Up @@ -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,
Expand Down
31 changes: 4 additions & 27 deletions nada_numpy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion nada_numpy/funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
17 changes: 10 additions & 7 deletions nada_numpy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -838,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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1346,6 +1348,7 @@ def add(self, other: _NadaRational, ignore_scale: bool = False) -> "SecretRation
SecretRational: Result of the addition.
"""
if not isinstance(other, (Rational, SecretRational)):
# 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:
Expand Down Expand Up @@ -1780,14 +1783,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":
"""
Expand Down Expand Up @@ -1972,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,
Expand Down Expand Up @@ -2670,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,
Expand Down
Loading

0 comments on commit f3c98b1

Please sign in to comment.