tinysmpc.py 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. # This is TinySMPC's top-level module that defines its user-facing API:
  2. # the three classes VirtualMachine, PrivateScalar, and SharedScalar.
  3. #
  4. # For modularity, almost all of the behavior of these classes is implemented
  5. # in functions imported from the other files here. Check them out!
  6. from .finite_ring import assert_is_element, mod, rand_element
  7. from .secret_sharing import n_from_shares, n_to_shares
  8. from .shared_addition import add_2sh, add_sh_pub
  9. from .shared_comparison import greater_than
  10. from .shared_multiplication import mult_2sh, mult_sh_pub
  11. class VirtualMachine():
  12. '''A very simple class that represents a machine's data.
  13. It just has a name and owns objects (PrivateScalars and Shares).'''
  14. def __init__(self, name):
  15. self.name = name
  16. self.objects = []
  17. def __repr__(self):
  18. return f'VirtualMachine(\'{self.name}\')\n - ' + '\n - '.join(map(str, self.objects))
  19. class PrivateScalar():
  20. '''A class that represents a secret number that belongs to a machine.'''
  21. def __init__(self, value, owner):
  22. self.value = value
  23. self.owner = owner
  24. owner.objects.append(self)
  25. def share(self, machines, Q=None):
  26. '''Split self.value into secret shares and distribute them across machines (tracked in a SharedScalar).'''
  27. shares = n_to_shares(self.value, machines, Q)
  28. return SharedScalar(shares, Q)
  29. def __repr__(self):
  30. return f'PrivateScalar({self.value}, \'{self.owner.name}\')'
  31. class SharedScalar():
  32. '''A class that tracks all secret shares that corresponds to one PrivateScalar.
  33. It supports *secure* arithmetic with other SharedScalars or integers (+, -, *).'''
  34. def __init__(self, shares, Q=None):
  35. assert all(share.Q == Q for share in shares)
  36. self.shares = shares
  37. self.share_of = {share.owner: share for share in shares}
  38. self.owners = {share.owner for share in shares}
  39. self.Q = Q
  40. def reconstruct(self, owner):
  41. '''Send all shares to one machine, and reconstruct the hidden value as a PrivateScalar.'''
  42. value = n_from_shares(self.shares, owner, self.Q)
  43. return PrivateScalar(value, owner)
  44. def __add__(self, other):
  45. '''Called by: self + other.'''
  46. if isinstance(other, int): return add_sh_pub(self, other)
  47. elif isinstance(other, SharedScalar): return add_2sh(self, other)
  48. def __radd__(self, other):
  49. '''Called by: other + self (when other is not a SharedScalar).'''
  50. return self.__add__(other)
  51. def __sub__(self, other):
  52. '''Called by: self - other.'''
  53. return self.__add__(-1*other)
  54. def __rsub__(self, other):
  55. '''Called by: other - self (when other is not a SharedScalar).'''
  56. return (-1*self).__add__(other)
  57. def __mul__(self, other):
  58. '''Called by: self * other.'''
  59. if isinstance(other, int): return mult_sh_pub(self, other)
  60. elif isinstance(other, SharedScalar): return mult_2sh(self, other)
  61. def __rmul__(self, other):
  62. '''Called by: other * self (when other is not a SharedScalar).'''
  63. return self.__mul__(other)
  64. def __pow__(self, other):
  65. '''Called by: self ** other. Only implemented when other is a public integer > 0.'''
  66. assert isinstance(other, int) and other > 0
  67. res = self
  68. for _ in range(other-1): res *= self
  69. return res
  70. def __gt__(self, other):
  71. '''Called by: self > other. Only implemented when other is a public integer.'''
  72. assert isinstance(other, int)
  73. return greater_than(self, other)
  74. def __repr__(self):
  75. return 'SharedScalar\n - ' + '\n - '.join(map(str, self.shares))
  76. def _assert_can_operate(self, other):
  77. '''Assert that two SharedScalars have the same owners and rings.'''
  78. assert self.owners == other.owners, f'{self}\nand\n{other}\ndo not have the same owners.'
  79. assert self.Q == other.Q, f'{self}\nand\n{other}\nare not over the same rings.'