From 532908a885850b1160f2cdc87cb2d9d346e114c3 Mon Sep 17 00:00:00 2001 From: rasswanth-s <43314053+rasswanth-s@users.noreply.github.com> Date: Tue, 25 May 2021 11:22:14 +0530 Subject: [PATCH 1/4] Added Hook method and property - RSTensor --- src/sympc/tensor/replicatedshare_tensor.py | 39 ++++++++++++---- .../tensor/replicatedshare_tensor_test.py | 44 ++++++++++++++++++- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/sympc/tensor/replicatedshare_tensor.py b/src/sympc/tensor/replicatedshare_tensor.py index f96d28b8..eb9aa88c 100755 --- a/src/sympc/tensor/replicatedshare_tensor.py +++ b/src/sympc/tensor/replicatedshare_tensor.py @@ -7,6 +7,8 @@ from typing import List from typing import Set +from sympc.tensor import ShareTensor + from .tensor import SyMPCTensor PROPERTIES_NEW_SHARE_TENSOR: Set[str] = {"T"} @@ -155,13 +157,23 @@ def hook_property(property_name: str) -> Any: """ def property_new_share_tensor_getter(_self: "ReplicatedSharedTensor") -> Any: - tensor = getattr(_self.tensor, property_name) - res = ReplicatedSharedTensor(session=_self.session) - res.tensor = tensor + tensor1 = getattr(_self.shares[0].tensor, property_name) + tensor2 = getattr(_self.shares[1].tensor, property_name) + share1 = ShareTensor(session=_self.session) + share1.tensor = ( + tensor1 # assign after instance creation to prevent FP encoding. + ) + share2 = ShareTensor(session=_self.session) + share2.tensor = ( + tensor2 # assign after instance creation to prevent FP encoding + ) + shares = [share1, share2] + res = ReplicatedSharedTensor(session=_self.session, shares=shares) + return res def property_getter(_self: "ReplicatedSharedTensor") -> Any: - prop = getattr(_self.tensor, property_name) + prop = getattr(_self.shares[0].tensor, property_name) return prop if property_name in PROPERTIES_NEW_SHARE_TENSOR: @@ -192,16 +204,25 @@ def hook_method(method_name: str) -> Callable[..., Any]: def method_new_rs_tensor( _self: "ReplicatedSharedTensor", *args: List[Any], **kwargs: Dict[Any, Any] ) -> Any: - method = getattr(_self.tensor, method_name) - tensor = method(*args, **kwargs) - res = ReplicatedSharedTensor(session=_self.session, shares=_self.shares) - res.tensor = tensor + tensor1 = getattr(_self.shares[0].tensor, method_name)(*args, **kwargs) + tensor2 = getattr(_self.shares[1].tensor, method_name)(*args, **kwargs) + share1 = ShareTensor(session=_self.session) + share1.tensor = ( + tensor1 # assign after instance creation to prevent FP encoding + ) + share2 = ShareTensor(data=tensor2, session=_self.session) + share2.tensor = ( + tensor2 # assign after instance creation to prevent FP encoding + ) + shares = [share1, share2] + res = ReplicatedSharedTensor(session=_self.session, shares=shares) + return res def method( _self: "ReplicatedSharedTensor", *args: List[Any], **kwargs: Dict[Any, Any] ) -> Any: - method = getattr(_self.tensor, method_name) + method = getattr(_self.shares[0].tensor, method_name) res = method(*args, **kwargs) return res diff --git a/tests/sympc/tensor/replicatedshare_tensor_test.py b/tests/sympc/tensor/replicatedshare_tensor_test.py index 993cfe1a..a0b36290 100755 --- a/tests/sympc/tensor/replicatedshare_tensor_test.py +++ b/tests/sympc/tensor/replicatedshare_tensor_test.py @@ -1,6 +1,48 @@ +# third party +import torch + +from sympc.session import Session +from sympc.session import SessionManager from sympc.tensor import ReplicatedSharedTensor +from sympc.tensor import ShareTensor -def test_import_RSTensor(): +def test_import_RSTensor() -> None: ReplicatedSharedTensor() + + +def test_hook_method(get_clients) -> None: + alice, bob = get_clients(2) + session = Session(parties=[alice, bob]) + SessionManager.setup_mpc(session) + + x = torch.randn(1, 3) + y = torch.randn(1, 3) # noqa: F841 + stx = ShareTensor(data=x, session=session) + sty = ShareTensor(data=y, session=session) + shares = [stx, sty] + + rst = ReplicatedSharedTensor(shares=shares, session=session) + + assert rst.numel() == stx.numel() + assert rst.t().shares[0] == stx.t() + assert rst.unsqueeze(dim=0).shares[0] == stx.unsqueeze(dim=0) + assert rst.view(3, 1).shares[0] == stx.view(3, 1) + assert rst.sum().shares[0] == stx.sum() + + +def test_hook_property(get_clients) -> None: + alice, bob = get_clients(2) + session = Session(parties=[alice, bob]) + SessionManager.setup_mpc(session) + + x = torch.randn(1, 3) + y = torch.randn(1, 3) # noqa: F841 + stx = ShareTensor(data=x, session=session) + sty = ShareTensor(data=y, session=session) + shares = [stx, sty] + + rst = ReplicatedSharedTensor(shares=shares, session=session) + + assert rst.T.shares[0] == stx.T From a3b1a41d1df66201007cb4d38a1dce8a12cd365a Mon Sep 17 00:00:00 2001 From: rasswanth-s <43314053+rasswanth-s@users.noreply.github.com> Date: Tue, 25 May 2021 18:09:13 +0530 Subject: [PATCH 2/4] Modified RSTensor to torch.Tensor --- src/sympc/tensor/replicatedshare_tensor.py | 66 +++++++++---------- .../tensor/replicatedshare_tensor_test.py | 21 +++--- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/sympc/tensor/replicatedshare_tensor.py b/src/sympc/tensor/replicatedshare_tensor.py index eb9aa88c..5760e30b 100755 --- a/src/sympc/tensor/replicatedshare_tensor.py +++ b/src/sympc/tensor/replicatedshare_tensor.py @@ -5,14 +5,19 @@ from typing import Callable from typing import Dict from typing import List +from typing import Optional from typing import Set +from typing import Union -from sympc.tensor import ShareTensor +# third party +import torch + +from sympc.session import Session from .tensor import SyMPCTensor -PROPERTIES_NEW_SHARE_TENSOR: Set[str] = {"T"} -METHODS_NEW_SHARE_TENSOR: Set[str] = {"unsqueeze", "view", "t", "sum", "clone"} +PROPERTIES_NEW_RS_TENSOR: Set[str] = {"T"} +METHODS_NEW_RS_TENSOR: Set[str] = {"unsqueeze", "view", "t", "sum", "clone"} class ReplicatedSharedTensor(metaclass=SyMPCTensor): @@ -32,11 +37,15 @@ class ReplicatedSharedTensor(metaclass=SyMPCTensor): METHODS_FORWARD = {"numel", "t", "unsqueeze", "view", "sum", "clone"} PROPERTIES_FORWARD = {"T"} - def __init__(self, shares=None, session=None): + def __init__( + self, + shares: Optional[Union[float, int, torch.Tensor]] = None, + session: Optional[Session] = None, + ): """Initialize ShareTensor. Args: - shares (Optional[List[ShareTensor]]): Shares from which RSTensor is created. + shares (Optional[Union[float,int,torch.Tensor]]): Shares from which RSTensor is created. session (Optional[Session]): The session. Defaults to None. """ self.session = session @@ -156,28 +165,24 @@ def hook_property(property_name: str) -> Any: A hooked property """ - def property_new_share_tensor_getter(_self: "ReplicatedSharedTensor") -> Any: - tensor1 = getattr(_self.shares[0].tensor, property_name) - tensor2 = getattr(_self.shares[1].tensor, property_name) - share1 = ShareTensor(session=_self.session) - share1.tensor = ( - tensor1 # assign after instance creation to prevent FP encoding. - ) - share2 = ShareTensor(session=_self.session) - share2.tensor = ( - tensor2 # assign after instance creation to prevent FP encoding - ) - shares = [share1, share2] + def property_new_rs_tensor_getter(_self: "ReplicatedSharedTensor") -> Any: + shares = [] + nr_parties = _self.session.nr_parties + + for i in range(nr_parties - 1): # each party has n-1 shares. + tensor = getattr(_self.shares[i], property_name) + shares.append(tensor) + res = ReplicatedSharedTensor(session=_self.session, shares=shares) return res def property_getter(_self: "ReplicatedSharedTensor") -> Any: - prop = getattr(_self.shares[0].tensor, property_name) + prop = getattr(_self.shares[0], property_name) return prop - if property_name in PROPERTIES_NEW_SHARE_TENSOR: - res = property(property_new_share_tensor_getter, None) + if property_name in PROPERTIES_NEW_RS_TENSOR: + res = property(property_new_rs_tensor_getter, None) else: res = property(property_getter, None) @@ -204,17 +209,12 @@ def hook_method(method_name: str) -> Callable[..., Any]: def method_new_rs_tensor( _self: "ReplicatedSharedTensor", *args: List[Any], **kwargs: Dict[Any, Any] ) -> Any: - tensor1 = getattr(_self.shares[0].tensor, method_name)(*args, **kwargs) - tensor2 = getattr(_self.shares[1].tensor, method_name)(*args, **kwargs) - share1 = ShareTensor(session=_self.session) - share1.tensor = ( - tensor1 # assign after instance creation to prevent FP encoding - ) - share2 = ShareTensor(data=tensor2, session=_self.session) - share2.tensor = ( - tensor2 # assign after instance creation to prevent FP encoding - ) - shares = [share1, share2] + shares = [] + nr_parties = _self.session.nr_parties + for i in range(nr_parties - 1): # each party has n-1 shares + tensor = getattr(_self.shares[i], method_name)(*args, **kwargs) + shares.append(tensor) + res = ReplicatedSharedTensor(session=_self.session, shares=shares) return res @@ -222,11 +222,11 @@ def method_new_rs_tensor( def method( _self: "ReplicatedSharedTensor", *args: List[Any], **kwargs: Dict[Any, Any] ) -> Any: - method = getattr(_self.shares[0].tensor, method_name) + method = getattr(_self.shares[0], method_name) res = method(*args, **kwargs) return res - if method_name in METHODS_NEW_SHARE_TENSOR: + if method_name in METHODS_NEW_RS_TENSOR: res = method_new_rs_tensor else: res = method diff --git a/tests/sympc/tensor/replicatedshare_tensor_test.py b/tests/sympc/tensor/replicatedshare_tensor_test.py index a0b36290..8c0d7fdf 100755 --- a/tests/sympc/tensor/replicatedshare_tensor_test.py +++ b/tests/sympc/tensor/replicatedshare_tensor_test.py @@ -4,7 +4,6 @@ from sympc.session import Session from sympc.session import SessionManager from sympc.tensor import ReplicatedSharedTensor -from sympc.tensor import ShareTensor def test_import_RSTensor() -> None: @@ -19,17 +18,15 @@ def test_hook_method(get_clients) -> None: x = torch.randn(1, 3) y = torch.randn(1, 3) # noqa: F841 - stx = ShareTensor(data=x, session=session) - sty = ShareTensor(data=y, session=session) - shares = [stx, sty] + shares = [x, y] rst = ReplicatedSharedTensor(shares=shares, session=session) - assert rst.numel() == stx.numel() - assert rst.t().shares[0] == stx.t() - assert rst.unsqueeze(dim=0).shares[0] == stx.unsqueeze(dim=0) - assert rst.view(3, 1).shares[0] == stx.view(3, 1) - assert rst.sum().shares[0] == stx.sum() + assert rst.numel() == x.numel() + assert (rst.t().shares[0] == x.t()).all() + assert (rst.unsqueeze(dim=0).shares[0] == x.unsqueeze(dim=0)).all() + assert (rst.view(3, 1).shares[0] == x.view(3, 1)).all() + assert (rst.sum().shares[0] == x.sum()).all() def test_hook_property(get_clients) -> None: @@ -39,10 +36,8 @@ def test_hook_property(get_clients) -> None: x = torch.randn(1, 3) y = torch.randn(1, 3) # noqa: F841 - stx = ShareTensor(data=x, session=session) - sty = ShareTensor(data=y, session=session) - shares = [stx, sty] + shares = [x, y] rst = ReplicatedSharedTensor(shares=shares, session=session) - assert rst.T.shares[0] == stx.T + assert (rst.T.shares[0] == x.T).all() From 93b1296d780af497d70f88f464cb14a2995f41f4 Mon Sep 17 00:00:00 2001 From: rasswanth-s <43314053+rasswanth-s@users.noreply.github.com> Date: Tue, 25 May 2021 21:44:52 +0530 Subject: [PATCH 3/4] Modified loop parameters,docstring,testcase --- src/sympc/tensor/replicatedshare_tensor.py | 16 ++++++++-------- .../sympc/tensor/replicatedshare_tensor_test.py | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sympc/tensor/replicatedshare_tensor.py b/src/sympc/tensor/replicatedshare_tensor.py index 5760e30b..d3188034 100755 --- a/src/sympc/tensor/replicatedshare_tensor.py +++ b/src/sympc/tensor/replicatedshare_tensor.py @@ -24,8 +24,9 @@ class ReplicatedSharedTensor(metaclass=SyMPCTensor): """RSTensor is used when a party holds more than a single share,required by various protocols. Arguments: - session (Session): the session - shares: The shares held by the party + shares (Optional[List[Union[float, int, torch.Tensor]]]): Shares list + from which RSTensor is created. + session (Optional[Session]): The session. Attributes: shares: The shares held by the party @@ -39,13 +40,14 @@ class ReplicatedSharedTensor(metaclass=SyMPCTensor): def __init__( self, - shares: Optional[Union[float, int, torch.Tensor]] = None, + shares: Optional[List[Union[float, int, torch.Tensor]]] = None, session: Optional[Session] = None, ): """Initialize ShareTensor. Args: - shares (Optional[Union[float,int,torch.Tensor]]): Shares from which RSTensor is created. + shares (Optional[List[Union[float, int, torch.Tensor]]]): Shares list + from which RSTensor is created. session (Optional[Session]): The session. Defaults to None. """ self.session = session @@ -167,9 +169,8 @@ def hook_property(property_name: str) -> Any: def property_new_rs_tensor_getter(_self: "ReplicatedSharedTensor") -> Any: shares = [] - nr_parties = _self.session.nr_parties - for i in range(nr_parties - 1): # each party has n-1 shares. + for i in range(len(_self.shares)): tensor = getattr(_self.shares[i], property_name) shares.append(tensor) @@ -210,8 +211,7 @@ def method_new_rs_tensor( _self: "ReplicatedSharedTensor", *args: List[Any], **kwargs: Dict[Any, Any] ) -> Any: shares = [] - nr_parties = _self.session.nr_parties - for i in range(nr_parties - 1): # each party has n-1 shares + for i in range(len(_self.shares)): tensor = getattr(_self.shares[i], method_name)(*args, **kwargs) shares.append(tensor) diff --git a/tests/sympc/tensor/replicatedshare_tensor_test.py b/tests/sympc/tensor/replicatedshare_tensor_test.py index 8c0d7fdf..d5e9096d 100755 --- a/tests/sympc/tensor/replicatedshare_tensor_test.py +++ b/tests/sympc/tensor/replicatedshare_tensor_test.py @@ -12,8 +12,8 @@ def test_import_RSTensor() -> None: def test_hook_method(get_clients) -> None: - alice, bob = get_clients(2) - session = Session(parties=[alice, bob]) + alice, bob, charlie = get_clients(3) + session = Session(parties=[alice, bob, charlie]) SessionManager.setup_mpc(session) x = torch.randn(1, 3) @@ -30,8 +30,8 @@ def test_hook_method(get_clients) -> None: def test_hook_property(get_clients) -> None: - alice, bob = get_clients(2) - session = Session(parties=[alice, bob]) + alice, bob, charlie = get_clients(3) + session = Session(parties=[alice, bob, charlie]) SessionManager.setup_mpc(session) x = torch.randn(1, 3) From b43f9495f5baddc875015c0b28128eb15961b7ef Mon Sep 17 00:00:00 2001 From: rasswanth-s <43314053+rasswanth-s@users.noreply.github.com> Date: Sun, 30 May 2021 00:05:48 +0530 Subject: [PATCH 4/4] Refactored and added more tests for RSTensor --- .../tensor/replicatedshare_tensor_test.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/sympc/tensor/replicatedshare_tensor_test.py b/tests/sympc/tensor/replicatedshare_tensor_test.py index d5e9096d..2fdb249b 100755 --- a/tests/sympc/tensor/replicatedshare_tensor_test.py +++ b/tests/sympc/tensor/replicatedshare_tensor_test.py @@ -12,12 +12,12 @@ def test_import_RSTensor() -> None: def test_hook_method(get_clients) -> None: - alice, bob, charlie = get_clients(3) - session = Session(parties=[alice, bob, charlie]) + clients = get_clients(3) + session = Session(parties=clients) SessionManager.setup_mpc(session) x = torch.randn(1, 3) - y = torch.randn(1, 3) # noqa: F841 + y = torch.randn(1, 3) shares = [x, y] rst = ReplicatedSharedTensor(shares=shares, session=session) @@ -28,16 +28,23 @@ def test_hook_method(get_clients) -> None: assert (rst.view(3, 1).shares[0] == x.view(3, 1)).all() assert (rst.sum().shares[0] == x.sum()).all() + assert rst.numel() == y.numel() + assert (rst.t().shares[1] == y.t()).all() + assert (rst.unsqueeze(dim=0).shares[1] == y.unsqueeze(dim=0)).all() + assert (rst.view(3, 1).shares[1] == y.view(3, 1)).all() + assert (rst.sum().shares[1] == y.sum()).all() + def test_hook_property(get_clients) -> None: - alice, bob, charlie = get_clients(3) - session = Session(parties=[alice, bob, charlie]) + clients = get_clients(3) + session = Session(parties=clients) SessionManager.setup_mpc(session) x = torch.randn(1, 3) - y = torch.randn(1, 3) # noqa: F841 + y = torch.randn(1, 3) shares = [x, y] rst = ReplicatedSharedTensor(shares=shares, session=session) assert (rst.T.shares[0] == x.T).all() + assert (rst.T.shares[1] == y.T).all()