Repository: OpenMined/PySyft
Pull request #245 (2017-09-21 13:23:52)

Added additive and multiplicative depth tracking #11
This can be used to predict to predict when a number is about to become undecryptable. (#11)
@MtDersvan @iamtrask 


Patch:
diff --git a/syft/he/paillier/basic.py b/syft/he/paillier/basic.py
index 24b3e0a2ba..856498d9c3 100644
--- a/syft/he/paillier/basic.py
+++ b/syft/he/paillier/basic.py
@@ -33,7 +33,9 @@ class PaillierTensor(TensorBase):
         if(type(tensor) == TensorBase):
             tensor = PaillierTensor(self.public_key, tensor.data)
 
-        return PaillierTensor(self.public_key, self.data + tensor.data, False)
+        ptensor = PaillierTensor(self.public_key, self.data + tensor.data, False)
+        ptensor._calc_add_depth(self, tensor)
+        return ptensor
 
     def __sub__(self, tensor):
         """Performs element-wise subtraction between two tensors"""
@@ -60,12 +62,15 @@ class PaillierTensor(TensorBase):
             if(not tensor.encrypted):
                 result = self.data * tensor.data
                 o = PaillierTensor(self.public_key, result, False)
+                o._calc_mul_depth(self, tensor)
                 return o
             else:
                 return NotImplemented
         else:
             op = self.data * float(tensor)
-            return PaillierTensor(self.public_key, op, False)
+            ptensor = PaillierTensor(self.public_key, op, False)
+            ptensor._calc_mul_depth(self, tensor)
+            return ptensor
 
     def __truediv__(self, tensor):
         """Performs element-wise division between two tensors"""
diff --git a/syft/tensor.py b/syft/tensor.py
index 5e21979515..8ed5efad8d 100644
--- a/syft/tensor.py
+++ b/syft/tensor.py
@@ -52,10 +52,29 @@ class TensorBase(object):
     matrix products.
     """
 
+    _mul_depth = 0
+    _add_depth = 0
+
     def __init__(self, arr_like, encrypted=False):
         self.data = _ensure_ndarray(arr_like)
         self.encrypted = encrypted
 
+    def _calc_mul_depth(self, tensor1, tensor2):
+        if isinstance(tensor1, TensorBase) and isinstance(tensor2, TensorBase):
+            self._mul_depth = max(tensor1._mul_depth, tensor2._mul_depth) + 1
+        elif isinstance(tensor1, TensorBase):
+            self._mul_depth = tensor1._mul_depth + 1
+        elif isinstance(tensor2, TensorBase):
+            self._mul_depth = tensor2._mul_depth + 1
+
+    def _calc_add_depth(self, tensor1, tensor2):
+        if isinstance(tensor1, TensorBase) and isinstance(tensor2, TensorBase):
+            self._add_depth = max(tensor1._add_depth, tensor2._add_depth) + 1
+        elif isinstance(tensor1, TensorBase):
+            self._add_depth = tensor1._add_depth + 1
+        elif isinstance(tensor2, TensorBase):
+            self._add_depth = tensor2._add_depth + 1
+
     def encrypt(self, pubkey):
         """Encrypts the Tensor using a Public Key"""
         if self.encrypted:


Test patch:
diff --git a/tests/test_paillier.py b/tests/test_paillier.py
index d2ace2e2f0..31efb6cacb 100644
--- a/tests/test_paillier.py
+++ b/tests/test_paillier.py
@@ -93,6 +93,15 @@ class AddTests(unittest.TestCase):
         x += x2
         self.assertTrue(s.decrypt(x) == np.array([4., 6., 8., 10., 12.]))
 
+    def testAddDepth(self):
+        p, s = KeyPair().generate()
+
+        x = PaillierTensor(p, np.array([1, 2, 3, 4, 5.]))
+        x2 = TensorBase(np.array([3, 4, 5, 6, 7.]))
+
+        x += x2
+        self.assertEqual(x._add_depth, 1)
+
 
 class MulTests(unittest.TestCase):
 
@@ -140,6 +149,15 @@ class MulTests(unittest.TestCase):
         x *= 2
         self.assertTrue(s.decrypt(x) == np.array([2., 4., 6., 8., 10.]))
 
+    def testMulDepth(self):
+        p, s = KeyPair().generate()
+
+        x = PaillierTensor(p, np.array([1, 2, 3, 4, 5.]))
+        x2 = TensorBase(np.array([3, 4, 5, 6, 7.]))
+
+        x *= x2
+        self.assertEqual(x._mul_depth, 1)
+
 
 class DivTests(unittest.TestCase):