shared_multiplication.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. # This module defines multiplication on SharedScalars, using the SPDZ
  2. # algorithm for multiplication [1].
  3. #
  4. # [1] https://bristolcrypto.blogspot.com/2016/10/what-is-spdz-part-2-circuit-evaluation.html
  5. # Small hack:
  6. #
  7. # We can't import the SharedScalar class in this module as that would
  8. # create a circular dependency.
  9. #
  10. # However, we'd obviously still like to be able to construct new
  11. # SharedScalars here when doing arithmetic. To be able to do so,
  12. # we can use `type(sh)` to get access to the SharedScalar class &
  13. # constructor.
  14. from .finite_ring import mod, rand_element
  15. from .secret_sharing import n_to_shares
  16. from random import choice
  17. def mult_2sh(sh1, sh2):
  18. '''Implements multiplication on two SharedScalars.'''
  19. # Make sure that these two SharedScalars are compatible
  20. sh1._assert_can_operate(sh2)
  21. # Generate a random multiplication triple (public)
  22. a, b = rand_element(sh1.Q), rand_element(sh1.Q)
  23. c = mod(a * b, sh1.Q)
  24. # Share the triple across all machines
  25. # (It'd be nicer to use the higher-level PrivateScalar.share() here,
  26. # but we don't have access to PrivateScalar in this module.)
  27. machines = list(sh1.owners)
  28. shared_a = type(sh1)(n_to_shares(a, machines, sh1.Q), sh1.Q)
  29. shared_b = type(sh1)(n_to_shares(b, machines, sh1.Q), sh1.Q)
  30. shared_c = type(sh1)(n_to_shares(c, machines, sh1.Q), sh1.Q)
  31. # Compute sh1 - a, sh2 - b (shared)
  32. shared_sh1_m_a = sh1 - shared_a
  33. shared_sh2_m_b = sh2 - shared_b
  34. # Reconstruct sh1 - a, sh2 - b (public)
  35. rand_machine = choice(machines)
  36. sh1_m_a = shared_sh1_m_a.reconstruct(rand_machine).value
  37. sh2_m_b = shared_sh2_m_b.reconstruct(rand_machine).value
  38. # Magic! Compute each machine's share of the product
  39. shared_prod = shared_c + (sh1_m_a * shared_b) + (sh2_m_b * shared_a) + (sh1_m_a * sh2_m_b)
  40. return shared_prod
  41. def mult_sh_pub(sh, pub):
  42. '''Implements multiplication on a SharedScalar and a public integer.'''
  43. # To do the multiplication, we multiply the integer with all shares
  44. prod_shares = [share * pub for share in sh.shares]
  45. return type(sh)(prod_shares, Q=sh.Q)